openvibers/openvibe.contracts Commits
Agent Streams S6: the contracts the chat plays mode needs. (#314)
Changes
@@@ -1,5 +1,16 @@# Changelog++## 0.304.0 — 2026-11-06++++- Give the id kinds the Agent Streams work needs a prefix: `newId('agent_stream')` is `ags_…` (an agent stream's id), `newId('play_request')` is `req_…` (a chat plays request) and `newId('sandbox_session')` is `sbs_…` (the sandbox desk). Without them a service that had to name one of these ids had to build the ULID itself, and `newId('ags')` threw.++++- Add `chat.play-request@1` (Agent Streams S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`; one open request per person at a time, and an account younger than a day cannot ask. The request carries its votes, its state (`queued`, `running`, `done`, `failed`, `skipped`, `removed` or `refused`), whether it is pinned, and the one-line reason it was refused (with the rule that refused it) when it was. A refused request carries no result; a finished one carries the outcome, the line the overlay and the voice said, and the scratch site the run left.++- Add `codes.sandbox-session@1`: the sandbox desk a chat plays session runs on. The desk is started with `--shared` — no profile, no keys, no person's files, public egress only and a fresh workspace, wiped at the end — and the session carries the owner's time box (5 to 30 minutes), the step budget, the cap (money and minutes), what it has spent, whether the owner armed it with Go, and the throwaway scratch site with the 24 hours it lives. `egress_public_only` is always true: no private address is reachable.++- `live.agent-stream-control@1` gains the control `wipe` (additive): Wipe now stops the run and resets the sandbox. The other four controls (pause, curtain, mute, end) keep their shape.++- `live.agent-stream@1` gains the mode `chatplays` (additive; the enum already carried it): a chat plays stream is public or unlisted, and it works the room's queue.++- Add the capabilities `chat.play_queue.read` and `chat.play_queue.write` for Codes, the task's service, acting for the stream's owner (a node token `on_behalf_of`), and name both in Chat's service manifest. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time, and the people and the votes in it belong to the room.++- Valid and invalid fixtures cover the queued, finished and refused requests, a request that is too long, a refusal without a reason, an unknown state, the armed and running sandbox sessions, a session with no cap, a time box outside 5 to 30 minutes, a sandbox that is not public-only, and the wipe control, so a missing field or a bad value fails the run.++## 0.303.0 — 2026-11-06- Add `chat.agent-digest@1` (Agent Streams S5): what a Co-pilot room said to an agent between two of its steps. The agent never reads the raw room: it asks Chat for a digest and gets at most ten items and 1,500 characters. Each item names who (the display name and the handle), what (cut to 200 characters), its kind (`question`, `suggestion` or `reaction`) and its upvotes; a repeated line is one item with the number behind it. Chat chooses what goes in (repeats grouped, greetings and spam dropped, the most-upvoted questions and suggestions first) and who is left out (a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages'). A link is kept as its domain only; the code and the commands stay as text.@@@ -11,6 +11,8 @@"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases","contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)","features": [++ "chat.play-request@1 and codes.sandbox-session@1 (the Agent Streams plan, S6): the queue a chat plays room keeps and the sandbox desk that works it, with the owner's time box, cap and Go, and the scratch site that lives 24 hours",++ "the capabilities chat.play_queue.read and chat.play_queue.write, for Codes acting for the stream's owner","chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream","the capabilities chat.agent_digest.read and chat.agent_poll.write, for Codes and Actor acting for the stream's owner","798 JSON Schemas with valid and invalid fixtures (at v0.210.0)",@@@ -9591,6 +9591,24 @@"visibility": "first-party","compatibility": "backward","status": "active"++ },++ {++ "id": "chat.play-request",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/play-request.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "codes.sandbox-session",++ "version": "1.0.0",++ "owner": "codes",++ "schema": "codes/sandbox-session.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"}]}nnew file mode 100644@@@ -0,0 +1,231 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/play-request.v1.json",++ "title": "ChatPlayRequest",++ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "request_id",++ "room",++ "author",++ "text",++ "votes",++ "state",++ "pinned",++ "created_at"++ ],++ "properties": {++ "request_id": {++ "type": "string",++ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The request's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."++ },++ "author": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle"++ ],++ "description": "Who asked. The handle and the display name only, never an id.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who asked."++ },++ "display_name": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 64,++ "description": "Their display name, when they have one."++ }++ }++ },++ "text": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "What the viewer asked for, as they typed it (at most 200 characters)."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many votes the request has. The count says nothing about who voted."++ },++ "voters": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted (one vote each)."++ },++ "state": {++ "enum": [++ "queued",++ "running",++ "done",++ "failed",++ "skipped",++ "removed",++ "refused"++ ],++ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."++ },++ "pinned": {++ "type": "boolean",++ "description": "A pinned request stays at the top of the queue until it is removed or it runs."++ },++ "created_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the request was asked for."++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the desk began it, or null while it waits."++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it finished, was skipped or was removed, or null while it stands."++ },++ "refusal": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "code",++ "reason"++ ],++ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",++ "properties": {++ "code": {++ "enum": [++ "platform_floor",++ "harm",++ "attack",++ "account_or_money",++ "account_too_new",++ "too_long",++ "already_open"++ ],++ "description": "Which rule turned it down."++ },++ "reason": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one-line reason shown in the room."++ }++ }++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "outcome",++ "line"++ ],++ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",++ "properties": {++ "outcome": {++ "enum": [++ "done",++ "failed",++ "timeout",++ "budget",++ "stopped"++ ],++ "description": "How it ended."++ },++ "line": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."++ },++ "scratch_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The throwaway scratch site the run left, when it left one."++ },++ "task_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "The Codes task that ran it."++ }++ }++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "refused"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "object"++ },++ "result": {++ "type": "null"++ }++ },++ "required": [++ "refusal"++ ]++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "not": {++ "const": "refused"++ }++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "null"++ }++ }++ }++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,187 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/codes/sandbox-session.v1.json",++ "title": "CodesSandboxSession",++ "description": "codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "session_id",++ "task",++ "owner",++ "state",++ "time_box_minutes",++ "step_budget",++ "cap",++ "spend",++ "armed",++ "egress_public_only"++ ],++ "properties": {++ "session_id": {++ "type": "string",++ "pattern": "^sbs_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The sandbox session's id (ULID, Crockford base32)."++ },++ "task": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "title"++ ],++ "description": "The task the desk is running for the queue.",++ "properties": {++ "id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The task's id in Codes."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ }++ }++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person the session spends their own allowance for."++ },++ "state": {++ "enum": [++ "idle",++ "armed",++ "running",++ "paused",++ "wiped",++ "ended"++ ],++ "description": "Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended."++ },++ "time_box_minutes": {++ "type": "integer",++ "minimum": 5,++ "maximum": 30,++ "description": "How long one request may run, in minutes (the owner sets 5 to 30; the default is 10)."++ },++ "step_budget": {++ "type": "integer",++ "minimum": 1,++ "description": "How many steps one request may take."++ },++ "cap": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "money_cents",++ "minutes"++ ],++ "description": "The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.",++ "properties": {++ "money_cents": {++ "type": "integer",++ "minimum": 0,++ "description": "The cap in cents."++ },++ "minutes": {++ "type": "integer",++ "minimum": 1,++ "description": "The cap in minutes of work."++ }++ }++ },++ "spend": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "money_cents",++ "seconds",++ "steps"++ ],++ "description": "What the session has spent so far.",++ "properties": {++ "money_cents": {++ "type": "integer",++ "minimum": 0++ },++ "seconds": {++ "type": "integer",++ "minimum": 0++ },++ "steps": {++ "type": "integer",++ "minimum": 0++ }++ }++ },++ "armed": {++ "type": "boolean",++ "description": "Whether the owner pressed Go. The first request of a session waits for it."++ },++ "armed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the owner pressed Go."++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "wiped_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When Wipe now reset the sandbox."++ },++ "egress_public_only": {++ "const": true,++ "description": "Always true: the sandbox reaches public addresses only, and no private address is reachable."++ },++ "scratch_site": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "url",++ "expires_at",++ "kept"++ ],++ "description": "The throwaway site the run left, or null before the first one.",++ "properties": {++ "url": {++ "type": "string",++ "format": "uri"++ },++ "expires_at": {++ "type": "string",++ "format": "date-time",++ "description": "When it is removed (24 hours after it was made, unless it is kept)."++ },++ "kept": {++ "type": "boolean",++ "description": "Whether the owner kept it past its 24 hours."++ }++ }++ }++ }++}@@@ -2,7 +2,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json","title": "LiveAgentStreamControl",-- "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",++ "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.","type": "object","additionalProperties": false,"required": [@@@ -16,7 +16,8 @@"pause","curtain","mute",-- "end"++ "end",++ "wipe"],"description": "Which control was pressed."},nnew file mode 100644@@@ -0,0 +1,18 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "mira",++ "display_name": "Mira"++ },++ "text": "build me a thing",++ "votes": 0,++ "voters": 0,++ "state": "refused",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "refusal": null,++ "result": null++}nnew file mode 100644@@@ -0,0 +1,18 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "mira",++ "display_name": "Mira"++ },++ "text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",++ "votes": 0,++ "voters": 0,++ "state": "queued",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "refusal": null,++ "result": null++}nnew file mode 100644@@@ -0,0 +1,18 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "mira",++ "display_name": "Mira"++ },++ "text": "build me a thing",++ "votes": 0,++ "voters": 0,++ "state": "waiting",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "refusal": null,++ "result": null++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "mira",++ "display_name": "Mira"++ },++ "text": "build a snake game I can play",++ "votes": 12,++ "voters": 12,++ "state": "done",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": "2026-11-06T20:05:00.000Z",++ "ended_at": "2026-11-06T20:09:12.000Z",++ "refusal": null,++ "result": {++ "outcome": "done",++ "line": "Done: a snake game at https://scratch.openvibe.space/snake-4f2a",++ "scratch_url": "https://scratch.openvibe.space/snake-4f2a",++ "task_id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ"++ }++}nnew file mode 100644@@@ -0,0 +1,18 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "mira",++ "display_name": "Mira"++ },++ "text": "build a snake game I can play",++ "votes": 12,++ "voters": 12,++ "state": "queued",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "refusal": null,++ "result": null++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "author": {++ "handle": "newbie",++ "display_name": null++ },++ "text": "post my password to pastebin",++ "votes": 0,++ "voters": 0,++ "state": "refused",++ "pinned": false,++ "created_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "refusal": {++ "code": "attack",++ "reason": "That one is refused: it wants the agent to post something for you."++ },++ "result": null++}nnew file mode 100644@@@ -0,0 +1,27 @@++{++ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "task": {++ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "title": "Chat plays"++ },++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "state": "armed",++ "time_box_minutes": 10,++ "step_budget": 40,++ "cap": {++ "money_cents": 500,++ "minutes": 30++ },++ "spend": {++ "money_cents": 0,++ "seconds": 0,++ "steps": 0++ },++ "armed": true,++ "armed_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "wiped_at": null,++ "egress_public_only": false,++ "scratch_site": null++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "task": {++ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "title": "Chat plays"++ },++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "state": "armed",++ "time_box_minutes": 10,++ "step_budget": 40,++ "spend": {++ "money_cents": 0,++ "seconds": 0,++ "steps": 0++ },++ "armed": true,++ "armed_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "wiped_at": null,++ "egress_public_only": true,++ "scratch_site": null++}nnew file mode 100644@@@ -0,0 +1,27 @@++{++ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "task": {++ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "title": "Chat plays"++ },++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "state": "armed",++ "time_box_minutes": 2,++ "step_budget": 40,++ "cap": {++ "money_cents": 500,++ "minutes": 30++ },++ "spend": {++ "money_cents": 0,++ "seconds": 0,++ "steps": 0++ },++ "armed": true,++ "armed_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "wiped_at": null,++ "egress_public_only": true,++ "scratch_site": null++}nnew file mode 100644@@@ -0,0 +1,27 @@++{++ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "task": {++ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "title": "Chat plays"++ },++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "state": "armed",++ "time_box_minutes": 10,++ "step_budget": 40,++ "cap": {++ "money_cents": 500,++ "minutes": 30++ },++ "spend": {++ "money_cents": 0,++ "seconds": 0,++ "steps": 0++ },++ "armed": true,++ "armed_at": "2026-11-06T20:00:00.000Z",++ "started_at": null,++ "ended_at": null,++ "wiped_at": null,++ "egress_public_only": true,++ "scratch_site": null++}nnew file mode 100644@@@ -0,0 +1,31 @@++{++ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "task": {++ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "title": "Chat plays"++ },++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "state": "running",++ "time_box_minutes": 10,++ "step_budget": 40,++ "cap": {++ "money_cents": 500,++ "minutes": 30++ },++ "spend": {++ "money_cents": 42,++ "seconds": 180,++ "steps": 6++ },++ "armed": true,++ "armed_at": "2026-11-06T20:00:00.000Z",++ "started_at": "2026-11-06T20:01:00.000Z",++ "ended_at": null,++ "wiped_at": null,++ "egress_public_only": true,++ "scratch_site": {++ "url": "https://scratch.openvibe.space/snake-4f2a",++ "expires_at": "2026-11-07T20:01:00.000Z",++ "kept": false++ }++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "control": "wipe",++ "by": {++ "handle": "owner",++ "role": "owner"++ },++ "at": "2026-11-06T20:30:00.000Z",++ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "paused_by": null++}@@@ -104615,7 +104615,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json","title": "LiveAgentStreamControl",-- "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",++ "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.","type": "object","additionalProperties": false,"required": [@@@ -104629,7 +104629,8 @@"pause","curtain","mute",-- "end"++ "end",++ "wipe"],"description": "Which control was pressed."},@@@ -105545,6 +105546,434 @@}}}++ },++ "chat.play-request": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/play-request.v1.json",++ "title": "ChatPlayRequest",++ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "request_id",++ "room",++ "author",++ "text",++ "votes",++ "state",++ "pinned",++ "created_at"++ ],++ "properties": {++ "request_id": {++ "type": "string",++ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The request's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."++ },++ "author": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle"++ ],++ "description": "Who asked. The handle and the display name only, never an id.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who asked."++ },++ "display_name": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 64,++ "description": "Their display name, when they have one."++ }++ }++ },++ "text": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "What the viewer asked for, as they typed it (at most 200 characters)."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many votes the request has. The count says nothing about who voted."++ },++ "voters": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted (one vote each)."++ },++ "state": {++ "enum": [++ "queued",++ "running",++ "done",++ "failed",++ "skipped",++ "removed",++ "refused"++ ],++ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."++ },++ "pinned": {++ "type": "boolean",++ "description": "A pinned request stays at the top of the queue until it is removed or it runs."++ },++ "created_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the request was asked for."++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the desk began it, or null while it waits."++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it finished, was skipped or was removed, or null while it stands."++ },++ "refusal": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "code",++ "reason"++ ],++ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",++ "properties": {++ "code": {++ "enum": [++ "platform_floor",++ "harm",++ "attack",++ "account_or_money",++ "account_too_new",++ "too_long",++ "already_open"++ ],++ "description": "Which rule turned it down."++ },++ "reason": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one-line reason shown in the room."++ }++ }++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "outcome",++ "line"++ ],++ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",++ "properties": {++ "outcome": {++ "enum": [++ "done",++ "failed",++ "timeout",++ "budget",++ "stopped"++ ],++ "description": "How it ended."++ },++ "line": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."++ },++ "scratch_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The throwaway scratch site the run left, when it left one."++ },++ "task_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "The Codes task that ran it."++ }++ }++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "refused"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "object"++ },++ "result": {++ "type": "null"++ }++ },++ "required": [++ "refusal"++ ]++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "not": {++ "const": "refused"++ }++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "null"++ }++ }++ }++ }++ ]++ }++ },++ "codes.sandbox-session": {++ "version": "1.0.0",++ "owner": "codes",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/codes/sandbox-session.v1.json",++ "title": "CodesSandboxSession",++ "description": "codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "session_id",++ "task",++ "owner",++ "state",++ "time_box_minutes",++ "step_budget",++ "cap",++ "spend",++ "armed",++ "egress_public_only"++ ],++ "properties": {++ "session_id": {++ "type": "string",++ "pattern": "^sbs_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The sandbox session's id (ULID, Crockford base32)."++ },++ "task": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "title"++ ],++ "description": "The task the desk is running for the queue.",++ "properties": {++ "id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The task's id in Codes."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ }++ }++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person the session spends their own allowance for."++ },++ "state": {++ "enum": [++ "idle",++ "armed",++ "running",++ "paused",++ "wiped",++ "ended"++ ],++ "description": "Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended."++ },++ "time_box_minutes": {++ "type": "integer",++ "minimum": 5,++ "maximum": 30,++ "description": "How long one request may run, in minutes (the owner sets 5 to 30; the default is 10)."++ },++ "step_budget": {++ "type": "integer",++ "minimum": 1,++ "description": "How many steps one request may take."++ },++ "cap": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "money_cents",++ "minutes"++ ],++ "description": "The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.",++ "properties": {++ "money_cents": {++ "type": "integer",++ "minimum": 0,++ "description": "The cap in cents."++ },++ "minutes": {++ "type": "integer",++ "minimum": 1,++ "description": "The cap in minutes of work."++ }++ }++ },++ "spend": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "money_cents",++ "seconds",++ "steps"++ ],++ "description": "What the session has spent so far.",++ "properties": {++ "money_cents": {++ "type": "integer",++ "minimum": 0++ },++ "seconds": {++ "type": "integer",++ "minimum": 0++ },++ "steps": {++ "type": "integer",++ "minimum": 0++ }++ }++ },++ "armed": {++ "type": "boolean",++ "description": "Whether the owner pressed Go. The first request of a session waits for it."++ },++ "armed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the owner pressed Go."++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "wiped_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When Wipe now reset the sandbox."++ },++ "egress_public_only": {++ "const": true,++ "description": "Always true: the sandbox reaches public addresses only, and no private address is reachable."++ },++ "scratch_site": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "url",++ "expires_at",++ "kept"++ ],++ "description": "The throwaway site the run left, or null before the first one.",++ "properties": {++ "url": {++ "type": "string",++ "format": "uri"++ },++ "expires_at": {++ "type": "string",++ "format": "date-time",++ "description": "When it is removed (24 hours after it was made, unless it is kept)."++ },++ "kept": {++ "type": "boolean",++ "description": "Whether the owner kept it past its 24 hours."++ }++ }++ }++ }++ }}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bench API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Billing API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Blog API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bot API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Chat API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3893,6 +3893,380 @@}}},++ "/internal/chat/rooms/agent{play}-queue": {++ "get": {++ "operationId": "get_internal_chat_rooms_agentplay_queue",++ "summary": "Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6).",++ "description": "**chat.play_queue.read** (first-party): Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6). GET /internal/chat/rooms/agent:play-queue answers chat.play-request@1: the requests of the room `agent:<ags_id>`, each with its votes and its state, the current request and the top of the queue. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of), so the queue it reads is the owner's room and nobody else's. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time.",++ "tags": [++ "chat.play_queue"++ ],++ "x-openvibe-capabilities": [++ "chat.play_queue.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-read",++ "security": [++ {++ "openvibeToken": [++ "chat.play_queue.read"++ ]++ }++ ],++ "x-openvibe-input": {++ "$ref": "#/components/schemas/chat.play-request.v1"++ },++ "parameters": [++ {++ "name": "play",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "request_id",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The request's id (ULID, Crockford base32)."++ },++ "description": "The request's id (ULID, Crockford base32)."++ },++ {++ "name": "room",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."++ },++ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."++ },++ {++ "name": "author",++ "in": "query",++ "required": true,++ "schema": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle"++ ],++ "description": "Who asked. The handle and the display name only, never an id.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who asked."++ },++ "display_name": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 64,++ "description": "Their display name, when they have one."++ }++ }++ },++ "description": "Who asked. The handle and the display name only, never an id."++ },++ {++ "name": "text",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "What the viewer asked for, as they typed it (at most 200 characters)."++ },++ "description": "What the viewer asked for, as they typed it (at most 200 characters)."++ },++ {++ "name": "votes",++ "in": "query",++ "required": true,++ "schema": {++ "type": "integer",++ "minimum": 0,++ "description": "How many votes the request has. The count says nothing about who voted."++ },++ "description": "How many votes the request has. The count says nothing about who voted."++ },++ {++ "name": "voters",++ "in": "query",++ "required": false,++ "schema": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted (one vote each)."++ },++ "description": "How many people voted (one vote each)."++ },++ {++ "name": "state",++ "in": "query",++ "required": true,++ "schema": {++ "enum": [++ "queued",++ "running",++ "done",++ "failed",++ "skipped",++ "removed",++ "refused"++ ],++ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."++ },++ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."++ },++ {++ "name": "pinned",++ "in": "query",++ "required": true,++ "schema": {++ "type": "boolean",++ "description": "A pinned request stays at the top of the queue until it is removed or it runs."++ },++ "description": "A pinned request stays at the top of the queue until it is removed or it runs."++ },++ {++ "name": "created_at",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "format": "date-time",++ "description": "When the request was asked for."++ },++ "description": "When the request was asked for."++ },++ {++ "name": "started_at",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the desk began it, or null while it waits."++ },++ "description": "When the desk began it, or null while it waits."++ },++ {++ "name": "ended_at",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it finished, was skipped or was removed, or null while it stands."++ },++ "description": "When it finished, was skipped or was removed, or null while it stands."++ },++ {++ "name": "refusal",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "code",++ "reason"++ ],++ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",++ "properties": {++ "code": {++ "enum": [++ "platform_floor",++ "harm",++ "attack",++ "account_or_money",++ "account_too_new",++ "too_long",++ "already_open"++ ],++ "description": "Which rule turned it down."++ },++ "reason": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one-line reason shown in the room."++ }++ }++ },++ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted."++ },++ {++ "name": "result",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "outcome",++ "line"++ ],++ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",++ "properties": {++ "outcome": {++ "enum": [++ "done",++ "failed",++ "timeout",++ "budget",++ "stopped"++ ],++ "description": "How it ended."++ },++ "line": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."++ },++ "scratch_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The throwaway scratch site the run left, when it left one."++ },++ "task_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "The Codes task that ran it."++ }++ }++ },++ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said."++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.play-request.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/internal/chat/rooms/agent{play}-queue/{request_id}": {++ "post": {++ "operationId": "post_internal_chat_rooms_agentplay_queue_request_id",++ "summary": "Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran.",++ "description": "**chat.play_queue.write** (first-party): Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran. POST /internal/chat/rooms/agent:play-queue/:request_id takes chat.play-request@1 and moves the request from queued to running, and records its outcome (done, failed, timeout, budget or stopped) with the one line the overlay and the voice say and the scratch site the run left. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never lets this capability ask for money, add a person to the queue or change a vote: the queue's people and votes belong to the room.",++ "tags": [++ "chat.play_queue"++ ],++ "x-openvibe-capabilities": [++ "chat.play_queue.write"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-write",++ "security": [++ {++ "openvibeToken": [++ "chat.play_queue.write"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.play-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "play",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "request_id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.play-request.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/internal/chat/rooms/agent{poll}": {"get": {"operationId": "get_internal_chat_rooms_agentpoll",@@@ -8055,6 +8429,235 @@}]},++ "chat.play-request.v1": {++ "title": "ChatPlayRequest",++ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "request_id",++ "room",++ "author",++ "text",++ "votes",++ "state",++ "pinned",++ "created_at"++ ],++ "properties": {++ "request_id": {++ "type": "string",++ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The request's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."++ },++ "author": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle"++ ],++ "description": "Who asked. The handle and the display name only, never an id.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who asked."++ },++ "display_name": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 64,++ "description": "Their display name, when they have one."++ }++ }++ },++ "text": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "What the viewer asked for, as they typed it (at most 200 characters)."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many votes the request has. The count says nothing about who voted."++ },++ "voters": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted (one vote each)."++ },++ "state": {++ "enum": [++ "queued",++ "running",++ "done",++ "failed",++ "skipped",++ "removed",++ "refused"++ ],++ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."++ },++ "pinned": {++ "type": "boolean",++ "description": "A pinned request stays at the top of the queue until it is removed or it runs."++ },++ "created_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the request was asked for."++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the desk began it, or null while it waits."++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it finished, was skipped or was removed, or null while it stands."++ },++ "refusal": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "code",++ "reason"++ ],++ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",++ "properties": {++ "code": {++ "enum": [++ "platform_floor",++ "harm",++ "attack",++ "account_or_money",++ "account_too_new",++ "too_long",++ "already_open"++ ],++ "description": "Which rule turned it down."++ },++ "reason": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one-line reason shown in the room."++ }++ }++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "outcome",++ "line"++ ],++ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",++ "properties": {++ "outcome": {++ "enum": [++ "done",++ "failed",++ "timeout",++ "budget",++ "stopped"++ ],++ "description": "How it ended."++ },++ "line": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."++ },++ "scratch_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The throwaway scratch site the run left, when it left one."++ },++ "task_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "The Codes task that ran it."++ }++ }++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "refused"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "object"++ },++ "result": {++ "type": "null"++ }++ },++ "required": [++ "refusal"++ ]++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "not": {++ "const": "refused"++ }++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "refusal": {++ "type": "null"++ }++ }++ }++ }++ ]++ },"chat.send-request.v1": {"title": "ChatSendRequest","description": "chat.send-request@1: what a sender hands OpenVibe.Chat to post a chat line (chat.message.send). From a browser, a frame on WS /ws/chat of type chat in the room the socket joined (the text is trimmed; empty or longer than 6000 characters is dropped, the channel's own max_message_length is enforced after that; a line starting with ! or / is a command, not a message). From Live's bridge, POST /internal/live/calls: a chat.live_bridge.write batch in which every op that sends a message (a chat or dm frame, db saveChatMessage, deployNotice) also needs chat.message.send; without it that op alone is refused. From a first-party service, POST /internal/chat/messages: one line (or one DM) that Chat stores, broadcasts to the room (with mirror, also to global chat and the streamer rooms), reads aloud (tts) and answers with the real id; applied once per (caller, key), the same key with another body gets 409.",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Community API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Coupons API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Deals API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Domains API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Events API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Food API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Games API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Host API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -47,8 +47,8 @@"service": "chat","name": "OpenVibe.Chat","origin": "https://openvibe.chat",-- "operations": 58,-- "capabilities": 22++ "operations": 60,++ "capabilities": 24},{"service": "codes",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Inventory API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.MediaHub API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Media API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Network API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRestream API",-- "version": "0.303.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Play API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Quest API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Report API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Reviews API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Run API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Search API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Services API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Sources API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Space API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tips API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Today API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tools API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Trade API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.VIP API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Vision API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Watch API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Wiki API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Work API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Zone API",-- "version": "0.303.0",-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.304.0",++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -294490,13 +294490,13 @@ export type ChatAgentPoll = {/** [email protected] (owner: live) *//**-- * live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.++ * live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.*/export interface LiveAgentStreamControl {/*** Which control was pressed.*/-- control: "pause" | "curtain" | "mute" | "end";++ control: "pause" | "curtain" | "mute" | "end" | "wipe";/*** Who pressed it: the handle and the role they hold. Never an id, never anything else about them.*/@@@ -294786,3 +294786,189 @@ export interface ChatTTSSpeakResult {rate?: number;voice_id?: string | null;}++++/** [email protected] (owner: chat) */++/**++ * chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.++ */++export type ChatPlayRequest = {++ [k: string]: unknown | undefined;++} & {++ /**++ * The request's id (ULID, Crockford base32).++ */++ request_id: string;++ /**++ * The room the request was made in: an agent stream's room, `agent:<ags_id>`.++ */++ room: string;++ /**++ * Who asked. The handle and the display name only, never an id.++ */++ author: {++ /**++ * The handle of the person who asked.++ */++ handle: string;++ /**++ * Their display name, when they have one.++ */++ display_name?: string | null;++ };++ /**++ * What the viewer asked for, as they typed it (at most 200 characters).++ */++ text: string;++ /**++ * How many votes the request has. The count says nothing about who voted.++ */++ votes: number;++ /**++ * How many people voted (one vote each).++ */++ voters?: number;++ /**++ * Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down).++ */++ state: "queued" | "running" | "done" | "failed" | "skipped" | "removed" | "refused";++ /**++ * A pinned request stays at the top of the queue until it is removed or it runs.++ */++ pinned: boolean;++ /**++ * When the request was asked for.++ */++ created_at: string;++ /**++ * When the desk began it, or null while it waits.++ */++ started_at?: string | null;++ /**++ * When it finished, was skipped or was removed, or null while it stands.++ */++ ended_at?: string | null;++ /**++ * Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.++ */++ refusal?: {++ /**++ * Which rule turned it down.++ */++ code: "platform_floor" | "harm" | "attack" | "account_or_money" | "account_too_new" | "too_long" | "already_open";++ /**++ * The one-line reason shown in the room.++ */++ reason: string;++ } | null;++ /**++ * How the run ended, once it ran: the outcome and the line the overlay and the voice said.++ */++ result?: {++ /**++ * How it ended.++ */++ outcome: "done" | "failed" | "timeout" | "budget" | "stopped";++ /**++ * The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'.++ */++ line: string;++ /**++ * The throwaway scratch site the run left, when it left one.++ */++ scratch_url?: string | null;++ /**++ * The Codes task that ran it.++ */++ task_id?: string | null;++ } | null;++};++++/** [email protected] (owner: codes) */++/**++ * codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.++ */++export interface CodesSandboxSession {++ /**++ * The sandbox session's id (ULID, Crockford base32).++ */++ session_id: string;++ /**++ * The task the desk is running for the queue.++ */++ task: {++ /**++ * The task's id in Codes.++ */++ id: string;++ title: string;++ };++ /**++ * The person the session spends their own allowance for.++ */++ owner: string;++ /**++ * Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended.++ */++ state: "idle" | "armed" | "running" | "paused" | "wiped" | "ended";++ /**++ * How long one request may run, in minutes (the owner sets 5 to 30; the default is 10).++ */++ time_box_minutes: number;++ /**++ * How many steps one request may take.++ */++ step_budget: number;++ /**++ * The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.++ */++ cap: {++ /**++ * The cap in cents.++ */++ money_cents: number;++ /**++ * The cap in minutes of work.++ */++ minutes: number;++ };++ /**++ * What the session has spent so far.++ */++ spend: {++ money_cents: number;++ seconds: number;++ steps: number;++ };++ /**++ * Whether the owner pressed Go. The first request of a session waits for it.++ */++ armed: boolean;++ /**++ * When the owner pressed Go.++ */++ armed_at?: string | null;++ started_at?: string | null;++ ended_at?: string | null;++ /**++ * When Wipe now reset the sandbox.++ */++ wiped_at?: string | null;++ /**++ * Always true: the sandbox reaches public addresses only, and no private address is reachable.++ */++ egress_public_only: true;++ /**++ * The throwaway site the run left, or null before the first one.++ */++ scratch_site?: {++ url: string;++ /**++ * When it is removed (24 hours after it was made, unless it is kept).++ */++ expires_at: string;++ /**++ * Whether the owner kept it past its 24 hours.++ */++ kept: boolean;++ } | null;++}@@@ -6,7 +6,7 @@const crypto = require('crypto');const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';--const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', consent: 'cns', job: 'job', task: 'tsk', watch: 'wch', wait: 'wai', observation: 'wco', check: 'ckr', subscription: 'sub', deploy: 'dpl', domain: 'dom', manifest: 'mfs', release: 'rel', site: 'sit', robot: 'rob', stream: 'std', webhook_delivery: 'whd', share: 'shr', device: 'dev', hook: 'hok', policy: 'pol', audit: 'aud' };++const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', consent: 'cns', job: 'job', task: 'tsk', watch: 'wch', wait: 'wai', observation: 'wco', check: 'ckr', subscription: 'sub', deploy: 'dpl', domain: 'dom', manifest: 'mfs', release: 'rel', site: 'sit', robot: 'rob', stream: 'std', webhook_delivery: 'whd', share: 'shr', device: 'dev', hook: 'hok', policy: 'pol', audit: 'aud', agent_stream: 'ags', play_request: 'req', sandbox_session: 'sbs' };const SLUG_TYPES = new Set(['service', 'system']);const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "chat.play_queue.read",++ "version": "1.0",++ "owner": "chat",++ "status": "active",++ "visibility": "first-party",++ "description": "Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6). GET /internal/chat/rooms/agent:play-queue answers chat.play-request@1: the requests of the room `agent:<ags_id>`, each with its votes and its state, the current request and the top of the queue. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of), so the queue it reads is the owner's room and nobody else's. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time.",++ "inputSchema": "chat.play-request@1",++ "outputSchema": "chat.play-request@1",++ "permissions": [++ "chat:read"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-read",++ "events": [],++ "implementedBy": [++ "GET /internal/chat/rooms/agent:play-queue"++ ]++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "chat.play_queue.write",++ "version": "1.0",++ "owner": "chat",++ "status": "active",++ "visibility": "first-party",++ "description": "Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran. POST /internal/chat/rooms/agent:play-queue/:request_id takes chat.play-request@1 and moves the request from queued to running, and records its outcome (done, failed, timeout, budget or stopped) with the one line the overlay and the voice say and the scratch site the run left. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never lets this capability ask for money, add a person to the queue or change a vote: the queue's people and votes belong to the room.",++ "inputSchema": "chat.play-request@1",++ "outputSchema": "chat.play-request@1",++ "permissions": [++ "chat:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-write",++ "events": [],++ "implementedBy": [++ "POST /internal/chat/rooms/agent:play-queue/:request_id"++ ]++}@@@ -1,5 +1,5 @@{-- "version": "0.4.0",++ "version": "0.5.0","contractRanges": {"openvibe-contracts": ">=0.13.0 <1.0.0"},@@@ -21,6 +21,8 @@"chat.inbox.read","chat.inbox.reply","chat.live_bridge.write",++ "chat.play_queue.read",++ "chat.play_queue.write","chat.message.send","chat.messages.read","chat.moderation.queue.read",@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.302.0",++ "version": "0.304.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.302.0",++ "version": "0.304.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.303.0",++ "version": "0.304.0","description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.","main": "index.js","types": "generated/typescript/index.d.ts",
@@ -1,5 +1,16 @@
@@ -1,5 +1,16 @@
# Changelog
# Changelog
+## 0.304.0 — 2026-11-06
+
+- Give the id kinds the Agent Streams work needs a prefix: `newId('agent_stream')` is `ags_…` (an agent stream's id), `newId('play_request')` is `req_…` (a chat plays request) and `newId('sandbox_session')` is `sbs_…` (the sandbox desk). Without them a service that had to name one of these ids had to build the ULID itself, and `newId('ags')` threw.
+
+- Add `chat.play-request@1` (Agent Streams S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`; one open request per person at a time, and an account younger than a day cannot ask. The request carries its votes, its state (`queued`, `running`, `done`, `failed`, `skipped`, `removed` or `refused`), whether it is pinned, and the one-line reason it was refused (with the rule that refused it) when it was. A refused request carries no result; a finished one carries the outcome, the line the overlay and the voice said, and the scratch site the run left.
+- Add `codes.sandbox-session@1`: the sandbox desk a chat plays session runs on. The desk is started with `--shared` — no profile, no keys, no person's files, public egress only and a fresh workspace, wiped at the end — and the session carries the owner's time box (5 to 30 minutes), the step budget, the cap (money and minutes), what it has spent, whether the owner armed it with Go, and the throwaway scratch site with the 24 hours it lives. `egress_public_only` is always true: no private address is reachable.
+- `live.agent-stream-control@1` gains the control `wipe` (additive): Wipe now stops the run and resets the sandbox. The other four controls (pause, curtain, mute, end) keep their shape.
+- `live.agent-stream@1` gains the mode `chatplays` (additive; the enum already carried it): a chat plays stream is public or unlisted, and it works the room's queue.
+- Add the capabilities `chat.play_queue.read` and `chat.play_queue.write` for Codes, the task's service, acting for the stream's owner (a node token `on_behalf_of`), and name both in Chat's service manifest. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time, and the people and the votes in it belong to the room.
+- Valid and invalid fixtures cover the queued, finished and refused requests, a request that is too long, a refusal without a reason, an unknown state, the armed and running sandbox sessions, a session with no cap, a time box outside 5 to 30 minutes, a sandbox that is not public-only, and the wipe control, so a missing field or a bad value fails the run.
+
## 0.303.0 — 2026-11-06
## 0.303.0 — 2026-11-06
- Add `chat.agent-digest@1` (Agent Streams S5): what a Co-pilot room said to an agent between two of its steps. The agent never reads the raw room: it asks Chat for a digest and gets at most ten items and 1,500 characters. Each item names who (the display name and the handle), what (cut to 200 characters), its kind (`question`, `suggestion` or `reaction`) and its upvotes; a repeated line is one item with the number behind it. Chat chooses what goes in (repeats grouped, greetings and spam dropped, the most-upvoted questions and suggestions first) and who is left out (a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages'). A link is kept as its domain only; the code and the commands stay as text.
- Add `chat.agent-digest@1` (Agent Streams S5): what a Co-pilot room said to an agent between two of its steps. The agent never reads the raw room: it asks Chat for a digest and gets at most ten items and 1,500 characters. Each item names who (the display name and the handle), what (cut to 200 characters), its kind (`question`, `suggestion` or `reaction`) and its upvotes; a repeated line is one item with the number behind it. Chat chooses what goes in (repeats grouped, greetings and spam dropped, the most-upvoted questions and suggestions first) and who is left out (a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages'). A link is kept as its domain only; the code and the commands stay as text.
@@ -11,6 +11,8 @@
@@ -11,6 +11,8 @@
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)",
"contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)",
"features": [
"features": [
+ "chat.play-request@1 and codes.sandbox-session@1 (the Agent Streams plan, S6): the queue a chat plays room keeps and the sandbox desk that works it, with the owner's time box, cap and Go, and the scratch site that lives 24 hours",
+ "the capabilities chat.play_queue.read and chat.play_queue.write, for Codes acting for the stream's owner",
"chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream",
"chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream",
"the capabilities chat.agent_digest.read and chat.agent_poll.write, for Codes and Actor acting for the stream's owner",
"the capabilities chat.agent_digest.read and chat.agent_poll.write, for Codes and Actor acting for the stream's owner",
"798 JSON Schemas with valid and invalid fixtures (at v0.210.0)",
"798 JSON Schemas with valid and invalid fixtures (at v0.210.0)",
@@ -9591,6 +9591,24 @@
@@ -9591,6 +9591,24 @@
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
+ },
+ {
+ "id": "chat.play-request",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/play-request.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "codes.sandbox-session",
+ "version": "1.0.0",
+ "owner": "codes",
+ "schema": "codes/sandbox-session.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
}
}
]
]
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,231 @@
@@ -0,0 +1,231 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/play-request.v1.json",
+ "title": "ChatPlayRequest",
+ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "request_id",
+ "room",
+ "author",
+ "text",
+ "votes",
+ "state",
+ "pinned",
+ "created_at"
+ ],
+ "properties": {
+ "request_id": {
+ "type": "string",
+ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The request's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "author": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle"
+ ],
+ "description": "Who asked. The handle and the display name only, never an id.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who asked."
+ },
+ "display_name": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 64,
+ "description": "Their display name, when they have one."
+ }
+ }
+ },
+ "text": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "What the viewer asked for, as they typed it (at most 200 characters)."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many votes the request has. The count says nothing about who voted."
+ },
+ "voters": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted (one vote each)."
+ },
+ "state": {
+ "enum": [
+ "queued",
+ "running",
+ "done",
+ "failed",
+ "skipped",
+ "removed",
+ "refused"
+ ],
+ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."
+ },
+ "pinned": {
+ "type": "boolean",
+ "description": "A pinned request stays at the top of the queue until it is removed or it runs."
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the request was asked for."
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the desk began it, or null while it waits."
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it finished, was skipped or was removed, or null while it stands."
+ },
+ "refusal": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "code",
+ "reason"
+ ],
+ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",
+ "properties": {
+ "code": {
+ "enum": [
+ "platform_floor",
+ "harm",
+ "attack",
+ "account_or_money",
+ "account_too_new",
+ "too_long",
+ "already_open"
+ ],
+ "description": "Which rule turned it down."
+ },
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one-line reason shown in the room."
+ }
+ }
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "outcome",
+ "line"
+ ],
+ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",
+ "properties": {
+ "outcome": {
+ "enum": [
+ "done",
+ "failed",
+ "timeout",
+ "budget",
+ "stopped"
+ ],
+ "description": "How it ended."
+ },
+ "line": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."
+ },
+ "scratch_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The throwaway scratch site the run left, when it left one."
+ },
+ "task_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The Codes task that ran it."
+ }
+ }
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "refused"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "object"
+ },
+ "result": {
+ "type": "null"
+ }
+ },
+ "required": [
+ "refusal"
+ ]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "not": {
+ "const": "refused"
+ }
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "null"
+ }
+ }
+ }
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,187 @@
@@ -0,0 +1,187 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/codes/sandbox-session.v1.json",
+ "title": "CodesSandboxSession",
+ "description": "codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "session_id",
+ "task",
+ "owner",
+ "state",
+ "time_box_minutes",
+ "step_budget",
+ "cap",
+ "spend",
+ "armed",
+ "egress_public_only"
+ ],
+ "properties": {
+ "session_id": {
+ "type": "string",
+ "pattern": "^sbs_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The sandbox session's id (ULID, Crockford base32)."
+ },
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "title"
+ ],
+ "description": "The task the desk is running for the queue.",
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The task's id in Codes."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ }
+ }
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person the session spends their own allowance for."
+ },
+ "state": {
+ "enum": [
+ "idle",
+ "armed",
+ "running",
+ "paused",
+ "wiped",
+ "ended"
+ ],
+ "description": "Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended."
+ },
+ "time_box_minutes": {
+ "type": "integer",
+ "minimum": 5,
+ "maximum": 30,
+ "description": "How long one request may run, in minutes (the owner sets 5 to 30; the default is 10)."
+ },
+ "step_budget": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many steps one request may take."
+ },
+ "cap": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "money_cents",
+ "minutes"
+ ],
+ "description": "The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.",
+ "properties": {
+ "money_cents": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "The cap in cents."
+ },
+ "minutes": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The cap in minutes of work."
+ }
+ }
+ },
+ "spend": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "money_cents",
+ "seconds",
+ "steps"
+ ],
+ "description": "What the session has spent so far.",
+ "properties": {
+ "money_cents": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "seconds": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "steps": {
+ "type": "integer",
+ "minimum": 0
+ }
+ }
+ },
+ "armed": {
+ "type": "boolean",
+ "description": "Whether the owner pressed Go. The first request of a session waits for it."
+ },
+ "armed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the owner pressed Go."
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "wiped_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When Wipe now reset the sandbox."
+ },
+ "egress_public_only": {
+ "const": true,
+ "description": "Always true: the sandbox reaches public addresses only, and no private address is reachable."
+ },
+ "scratch_site": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "url",
+ "expires_at",
+ "kept"
+ ],
+ "description": "The throwaway site the run left, or null before the first one.",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri"
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When it is removed (24 hours after it was made, unless it is kept)."
+ },
+ "kept": {
+ "type": "boolean",
+ "description": "Whether the owner kept it past its 24 hours."
+ }
+ }
+ }
+ }
+}
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json",
"$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json",
"title": "LiveAgentStreamControl",
"title": "LiveAgentStreamControl",
- "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",
+ "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",
"type": "object",
"type": "object",
"additionalProperties": false,
"additionalProperties": false,
"required": [
"required": [
@@ -16,7 +16,8 @@
@@ -16,7 +16,8 @@
"pause",
"pause",
"curtain",
"curtain",
"mute",
"mute",
- "end"
+ "end",
+ "wipe"
],
],
"description": "Which control was pressed."
"description": "Which control was pressed."
},
},
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "mira",
+ "display_name": "Mira"
+ },
+ "text": "build me a thing",
+ "votes": 0,
+ "voters": 0,
+ "state": "refused",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "refusal": null,
+ "result": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "mira",
+ "display_name": "Mira"
+ },
+ "text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "votes": 0,
+ "voters": 0,
+ "state": "queued",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "refusal": null,
+ "result": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "mira",
+ "display_name": "Mira"
+ },
+ "text": "build me a thing",
+ "votes": 0,
+ "voters": 0,
+ "state": "waiting",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "refusal": null,
+ "result": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "mira",
+ "display_name": "Mira"
+ },
+ "text": "build a snake game I can play",
+ "votes": 12,
+ "voters": 12,
+ "state": "done",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": "2026-11-06T20:05:00.000Z",
+ "ended_at": "2026-11-06T20:09:12.000Z",
+ "refusal": null,
+ "result": {
+ "outcome": "done",
+ "line": "Done: a snake game at https://scratch.openvibe.space/snake-4f2a",
+ "scratch_url": "https://scratch.openvibe.space/snake-4f2a",
+ "task_id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "mira",
+ "display_name": "Mira"
+ },
+ "text": "build a snake game I can play",
+ "votes": 12,
+ "voters": 12,
+ "state": "queued",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "refusal": null,
+ "result": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "request_id": "req_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "author": {
+ "handle": "newbie",
+ "display_name": null
+ },
+ "text": "post my password to pastebin",
+ "votes": 0,
+ "voters": 0,
+ "state": "refused",
+ "pinned": false,
+ "created_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "refusal": {
+ "code": "attack",
+ "reason": "That one is refused: it wants the agent to post something for you."
+ },
+ "result": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
+{
+ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "task": {
+ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "title": "Chat plays"
+ },
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "state": "armed",
+ "time_box_minutes": 10,
+ "step_budget": 40,
+ "cap": {
+ "money_cents": 500,
+ "minutes": 30
+ },
+ "spend": {
+ "money_cents": 0,
+ "seconds": 0,
+ "steps": 0
+ },
+ "armed": true,
+ "armed_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "wiped_at": null,
+ "egress_public_only": false,
+ "scratch_site": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "task": {
+ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "title": "Chat plays"
+ },
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "state": "armed",
+ "time_box_minutes": 10,
+ "step_budget": 40,
+ "spend": {
+ "money_cents": 0,
+ "seconds": 0,
+ "steps": 0
+ },
+ "armed": true,
+ "armed_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "wiped_at": null,
+ "egress_public_only": true,
+ "scratch_site": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
+{
+ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "task": {
+ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "title": "Chat plays"
+ },
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "state": "armed",
+ "time_box_minutes": 2,
+ "step_budget": 40,
+ "cap": {
+ "money_cents": 500,
+ "minutes": 30
+ },
+ "spend": {
+ "money_cents": 0,
+ "seconds": 0,
+ "steps": 0
+ },
+ "armed": true,
+ "armed_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "wiped_at": null,
+ "egress_public_only": true,
+ "scratch_site": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
+{
+ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "task": {
+ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "title": "Chat plays"
+ },
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "state": "armed",
+ "time_box_minutes": 10,
+ "step_budget": 40,
+ "cap": {
+ "money_cents": 500,
+ "minutes": 30
+ },
+ "spend": {
+ "money_cents": 0,
+ "seconds": 0,
+ "steps": 0
+ },
+ "armed": true,
+ "armed_at": "2026-11-06T20:00:00.000Z",
+ "started_at": null,
+ "ended_at": null,
+ "wiped_at": null,
+ "egress_public_only": true,
+ "scratch_site": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
+{
+ "session_id": "sbs_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "task": {
+ "id": "tsk_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "title": "Chat plays"
+ },
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "state": "running",
+ "time_box_minutes": 10,
+ "step_budget": 40,
+ "cap": {
+ "money_cents": 500,
+ "minutes": 30
+ },
+ "spend": {
+ "money_cents": 42,
+ "seconds": 180,
+ "steps": 6
+ },
+ "armed": true,
+ "armed_at": "2026-11-06T20:00:00.000Z",
+ "started_at": "2026-11-06T20:01:00.000Z",
+ "ended_at": null,
+ "wiped_at": null,
+ "egress_public_only": true,
+ "scratch_site": {
+ "url": "https://scratch.openvibe.space/snake-4f2a",
+ "expires_at": "2026-11-07T20:01:00.000Z",
+ "kept": false
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "control": "wipe",
+ "by": {
+ "handle": "owner",
+ "role": "owner"
+ },
+ "at": "2026-11-06T20:30:00.000Z",
+ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "paused_by": null
+}
@@ -104615,7 +104615,7 @@
@@ -104615,7 +104615,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json",
"$id": "https://openvibe.network/contracts/live/agent-stream-control.v1.json",
"title": "LiveAgentStreamControl",
"title": "LiveAgentStreamControl",
- "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",
+ "description": "live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.",
"type": "object",
"type": "object",
"additionalProperties": false,
"additionalProperties": false,
"required": [
"required": [
@@ -104629,7 +104629,8 @@
@@ -104629,7 +104629,8 @@
"pause",
"pause",
"curtain",
"curtain",
"mute",
"mute",
- "end"
+ "end",
+ "wipe"
],
],
"description": "Which control was pressed."
"description": "Which control was pressed."
},
},
@@ -105545,6 +105546,434 @@
@@ -105545,6 +105546,434 @@
}
}
}
}
}
}
+ },
+ "chat.play-request": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/play-request.v1.json",
+ "title": "ChatPlayRequest",
+ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "request_id",
+ "room",
+ "author",
+ "text",
+ "votes",
+ "state",
+ "pinned",
+ "created_at"
+ ],
+ "properties": {
+ "request_id": {
+ "type": "string",
+ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The request's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "author": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle"
+ ],
+ "description": "Who asked. The handle and the display name only, never an id.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who asked."
+ },
+ "display_name": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 64,
+ "description": "Their display name, when they have one."
+ }
+ }
+ },
+ "text": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "What the viewer asked for, as they typed it (at most 200 characters)."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many votes the request has. The count says nothing about who voted."
+ },
+ "voters": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted (one vote each)."
+ },
+ "state": {
+ "enum": [
+ "queued",
+ "running",
+ "done",
+ "failed",
+ "skipped",
+ "removed",
+ "refused"
+ ],
+ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."
+ },
+ "pinned": {
+ "type": "boolean",
+ "description": "A pinned request stays at the top of the queue until it is removed or it runs."
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the request was asked for."
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the desk began it, or null while it waits."
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it finished, was skipped or was removed, or null while it stands."
+ },
+ "refusal": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "code",
+ "reason"
+ ],
+ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",
+ "properties": {
+ "code": {
+ "enum": [
+ "platform_floor",
+ "harm",
+ "attack",
+ "account_or_money",
+ "account_too_new",
+ "too_long",
+ "already_open"
+ ],
+ "description": "Which rule turned it down."
+ },
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one-line reason shown in the room."
+ }
+ }
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "outcome",
+ "line"
+ ],
+ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",
+ "properties": {
+ "outcome": {
+ "enum": [
+ "done",
+ "failed",
+ "timeout",
+ "budget",
+ "stopped"
+ ],
+ "description": "How it ended."
+ },
+ "line": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."
+ },
+ "scratch_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The throwaway scratch site the run left, when it left one."
+ },
+ "task_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The Codes task that ran it."
+ }
+ }
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "refused"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "object"
+ },
+ "result": {
+ "type": "null"
+ }
+ },
+ "required": [
+ "refusal"
+ ]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "not": {
+ "const": "refused"
+ }
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "null"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "codes.sandbox-session": {
+ "version": "1.0.0",
+ "owner": "codes",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/codes/sandbox-session.v1.json",
+ "title": "CodesSandboxSession",
+ "description": "codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "session_id",
+ "task",
+ "owner",
+ "state",
+ "time_box_minutes",
+ "step_budget",
+ "cap",
+ "spend",
+ "armed",
+ "egress_public_only"
+ ],
+ "properties": {
+ "session_id": {
+ "type": "string",
+ "pattern": "^sbs_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The sandbox session's id (ULID, Crockford base32)."
+ },
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "title"
+ ],
+ "description": "The task the desk is running for the queue.",
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The task's id in Codes."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ }
+ }
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person the session spends their own allowance for."
+ },
+ "state": {
+ "enum": [
+ "idle",
+ "armed",
+ "running",
+ "paused",
+ "wiped",
+ "ended"
+ ],
+ "description": "Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended."
+ },
+ "time_box_minutes": {
+ "type": "integer",
+ "minimum": 5,
+ "maximum": 30,
+ "description": "How long one request may run, in minutes (the owner sets 5 to 30; the default is 10)."
+ },
+ "step_budget": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many steps one request may take."
+ },
+ "cap": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "money_cents",
+ "minutes"
+ ],
+ "description": "The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.",
+ "properties": {
+ "money_cents": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "The cap in cents."
+ },
+ "minutes": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The cap in minutes of work."
+ }
+ }
+ },
+ "spend": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "money_cents",
+ "seconds",
+ "steps"
+ ],
+ "description": "What the session has spent so far.",
+ "properties": {
+ "money_cents": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "seconds": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "steps": {
+ "type": "integer",
+ "minimum": 0
+ }
+ }
+ },
+ "armed": {
+ "type": "boolean",
+ "description": "Whether the owner pressed Go. The first request of a session waits for it."
+ },
+ "armed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the owner pressed Go."
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "wiped_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When Wipe now reset the sandbox."
+ },
+ "egress_public_only": {
+ "const": true,
+ "description": "Always true: the sandbox reaches public addresses only, and no private address is reachable."
+ },
+ "scratch_site": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "url",
+ "expires_at",
+ "kept"
+ ],
+ "description": "The throwaway site the run left, or null before the first one.",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri"
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When it is removed (24 hours after it was made, unless it is kept)."
+ },
+ "kept": {
+ "type": "boolean",
+ "description": "Whether the owner kept it past its 24 hours."
+ }
+ }
+ }
+ }
+ }
}
}
}
}
}
}
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Actor API",
"title": "OpenVibe.Actor API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.AI API",
"title": "OpenVibe.AI API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bench API",
"title": "OpenVibe.Bench API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Billing API",
"title": "OpenVibe.Billing API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Blog API",
"title": "OpenVibe.Blog API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bot API",
"title": "OpenVibe.Bot API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Chat API",
"title": "OpenVibe.Chat API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3893,6 +3893,380 @@
@@ -3893,6 +3893,380 @@
}
}
}
}
},
},
+ "/internal/chat/rooms/agent{play}-queue": {
+ "get": {
+ "operationId": "get_internal_chat_rooms_agentplay_queue",
+ "summary": "Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6).",
+ "description": "**chat.play_queue.read** (first-party): Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6). GET /internal/chat/rooms/agent:play-queue answers chat.play-request@1: the requests of the room `agent:<ags_id>`, each with its votes and its state, the current request and the top of the queue. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of), so the queue it reads is the owner's room and nobody else's. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time.",
+ "tags": [
+ "chat.play_queue"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.play_queue.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.play_queue.read"
+ ]
+ }
+ ],
+ "x-openvibe-input": {
+ "$ref": "#/components/schemas/chat.play-request.v1"
+ },
+ "parameters": [
+ {
+ "name": "play",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "request_id",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The request's id (ULID, Crockford base32)."
+ },
+ "description": "The request's id (ULID, Crockford base32)."
+ },
+ {
+ "name": "room",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."
+ },
+ {
+ "name": "author",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle"
+ ],
+ "description": "Who asked. The handle and the display name only, never an id.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who asked."
+ },
+ "display_name": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 64,
+ "description": "Their display name, when they have one."
+ }
+ }
+ },
+ "description": "Who asked. The handle and the display name only, never an id."
+ },
+ {
+ "name": "text",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "What the viewer asked for, as they typed it (at most 200 characters)."
+ },
+ "description": "What the viewer asked for, as they typed it (at most 200 characters)."
+ },
+ {
+ "name": "votes",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many votes the request has. The count says nothing about who voted."
+ },
+ "description": "How many votes the request has. The count says nothing about who voted."
+ },
+ {
+ "name": "voters",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted (one vote each)."
+ },
+ "description": "How many people voted (one vote each)."
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "enum": [
+ "queued",
+ "running",
+ "done",
+ "failed",
+ "skipped",
+ "removed",
+ "refused"
+ ],
+ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."
+ },
+ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."
+ },
+ {
+ "name": "pinned",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "description": "A pinned request stays at the top of the queue until it is removed or it runs."
+ },
+ "description": "A pinned request stays at the top of the queue until it is removed or it runs."
+ },
+ {
+ "name": "created_at",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the request was asked for."
+ },
+ "description": "When the request was asked for."
+ },
+ {
+ "name": "started_at",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the desk began it, or null while it waits."
+ },
+ "description": "When the desk began it, or null while it waits."
+ },
+ {
+ "name": "ended_at",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it finished, was skipped or was removed, or null while it stands."
+ },
+ "description": "When it finished, was skipped or was removed, or null while it stands."
+ },
+ {
+ "name": "refusal",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "code",
+ "reason"
+ ],
+ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",
+ "properties": {
+ "code": {
+ "enum": [
+ "platform_floor",
+ "harm",
+ "attack",
+ "account_or_money",
+ "account_too_new",
+ "too_long",
+ "already_open"
+ ],
+ "description": "Which rule turned it down."
+ },
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one-line reason shown in the room."
+ }
+ }
+ },
+ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted."
+ },
+ {
+ "name": "result",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "outcome",
+ "line"
+ ],
+ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",
+ "properties": {
+ "outcome": {
+ "enum": [
+ "done",
+ "failed",
+ "timeout",
+ "budget",
+ "stopped"
+ ],
+ "description": "How it ended."
+ },
+ "line": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."
+ },
+ "scratch_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The throwaway scratch site the run left, when it left one."
+ },
+ "task_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The Codes task that ran it."
+ }
+ }
+ },
+ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said."
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.play-request.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/internal/chat/rooms/agent{play}-queue/{request_id}": {
+ "post": {
+ "operationId": "post_internal_chat_rooms_agentplay_queue_request_id",
+ "summary": "Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran.",
+ "description": "**chat.play_queue.write** (first-party): Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran. POST /internal/chat/rooms/agent:play-queue/:request_id takes chat.play-request@1 and moves the request from queued to running, and records its outcome (done, failed, timeout, budget or stopped) with the one line the overlay and the voice say and the scratch site the run left. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never lets this capability ask for money, add a person to the queue or change a vote: the queue's people and votes belong to the room.",
+ "tags": [
+ "chat.play_queue"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.play_queue.write"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.play_queue.write"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.play-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "play",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "request_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.play-request.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/internal/chat/rooms/agent{poll}": {
"/internal/chat/rooms/agent{poll}": {
"get": {
"get": {
"operationId": "get_internal_chat_rooms_agentpoll",
"operationId": "get_internal_chat_rooms_agentpoll",
@@ -8055,6 +8429,235 @@
@@ -8055,6 +8429,235 @@
}
}
]
]
},
},
+ "chat.play-request.v1": {
+ "title": "ChatPlayRequest",
+ "description": "chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "request_id",
+ "room",
+ "author",
+ "text",
+ "votes",
+ "state",
+ "pinned",
+ "created_at"
+ ],
+ "properties": {
+ "request_id": {
+ "type": "string",
+ "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The request's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the request was made in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "author": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle"
+ ],
+ "description": "Who asked. The handle and the display name only, never an id.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who asked."
+ },
+ "display_name": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 64,
+ "description": "Their display name, when they have one."
+ }
+ }
+ },
+ "text": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "What the viewer asked for, as they typed it (at most 200 characters)."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many votes the request has. The count says nothing about who voted."
+ },
+ "voters": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted (one vote each)."
+ },
+ "state": {
+ "enum": [
+ "queued",
+ "running",
+ "done",
+ "failed",
+ "skipped",
+ "removed",
+ "refused"
+ ],
+ "description": "Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down)."
+ },
+ "pinned": {
+ "type": "boolean",
+ "description": "A pinned request stays at the top of the queue until it is removed or it runs."
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the request was asked for."
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the desk began it, or null while it waits."
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it finished, was skipped or was removed, or null while it stands."
+ },
+ "refusal": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "code",
+ "reason"
+ ],
+ "description": "Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.",
+ "properties": {
+ "code": {
+ "enum": [
+ "platform_floor",
+ "harm",
+ "attack",
+ "account_or_money",
+ "account_too_new",
+ "too_long",
+ "already_open"
+ ],
+ "description": "Which rule turned it down."
+ },
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one-line reason shown in the room."
+ }
+ }
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "outcome",
+ "line"
+ ],
+ "description": "How the run ended, once it ran: the outcome and the line the overlay and the voice said.",
+ "properties": {
+ "outcome": {
+ "enum": [
+ "done",
+ "failed",
+ "timeout",
+ "budget",
+ "stopped"
+ ],
+ "description": "How it ended."
+ },
+ "line": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'."
+ },
+ "scratch_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The throwaway scratch site the run left, when it left one."
+ },
+ "task_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The Codes task that ran it."
+ }
+ }
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "refused"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "object"
+ },
+ "result": {
+ "type": "null"
+ }
+ },
+ "required": [
+ "refusal"
+ ]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "not": {
+ "const": "refused"
+ }
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "refusal": {
+ "type": "null"
+ }
+ }
+ }
+ }
+ ]
+ },
"chat.send-request.v1": {
"chat.send-request.v1": {
"title": "ChatSendRequest",
"title": "ChatSendRequest",
"description": "chat.send-request@1: what a sender hands OpenVibe.Chat to post a chat line (chat.message.send). From a browser, a frame on WS /ws/chat of type chat in the room the socket joined (the text is trimmed; empty or longer than 6000 characters is dropped, the channel's own max_message_length is enforced after that; a line starting with ! or / is a command, not a message). From Live's bridge, POST /internal/live/calls: a chat.live_bridge.write batch in which every op that sends a message (a chat or dm frame, db saveChatMessage, deployNotice) also needs chat.message.send; without it that op alone is refused. From a first-party service, POST /internal/chat/messages: one line (or one DM) that Chat stores, broadcasts to the room (with mirror, also to global chat and the streamer rooms), reads aloud (tts) and answers with the real id; applied once per (caller, key), the same key with another body gets 409.",
"description": "chat.send-request@1: what a sender hands OpenVibe.Chat to post a chat line (chat.message.send). From a browser, a frame on WS /ws/chat of type chat in the room the socket joined (the text is trimmed; empty or longer than 6000 characters is dropped, the channel's own max_message_length is enforced after that; a line starting with ! or / is a command, not a message). From Live's bridge, POST /internal/live/calls: a chat.live_bridge.write batch in which every op that sends a message (a chat or dm frame, db saveChatMessage, deployNotice) also needs chat.message.send; without it that op alone is refused. From a first-party service, POST /internal/chat/messages: one line (or one DM) that Chat stores, broadcasts to the room (with mirror, also to global chat and the streamer rooms), reads aloud (tts) and answers with the real id; applied once per (caller, key), the same key with another body gets 409.",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Community API",
"title": "OpenVibe.Community API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Coupons API",
"title": "OpenVibe.Coupons API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Deals API",
"title": "OpenVibe.Deals API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Domains API",
"title": "OpenVibe.Domains API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Events API",
"title": "OpenVibe.Events API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Food API",
"title": "OpenVibe.Food API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Games API",
"title": "OpenVibe.Games API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Host API",
"title": "OpenVibe.Host API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -47,8 +47,8 @@
@@ -47,8 +47,8 @@
"service": "chat",
"service": "chat",
"name": "OpenVibe.Chat",
"name": "OpenVibe.Chat",
"origin": "https://openvibe.chat",
"origin": "https://openvibe.chat",
- "operations": 58,
- "capabilities": 22
+ "operations": 60,
+ "capabilities": 24
},
},
{
{
"service": "codes",
"service": "codes",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Inventory API",
"title": "OpenVibe.Inventory API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Live API",
"title": "OpenVibe.Live API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.MediaHub API",
"title": "OpenVibe.MediaHub API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Media API",
"title": "OpenVibe.Media API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Network API",
"title": "OpenVibe.Network API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.News API",
"title": "OpenVibe.News API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRestream API",
"title": "OpenRestream API",
- "version": "0.303.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Play API",
"title": "OpenVibe.Play API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Quest API",
"title": "OpenVibe.Quest API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Report API",
"title": "OpenVibe.Report API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Reviews API",
"title": "OpenVibe.Reviews API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Run API",
"title": "OpenVibe.Run API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Search API",
"title": "OpenVibe.Search API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Services API",
"title": "OpenVibe.Services API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Sources API",
"title": "OpenVibe.Sources API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Space API",
"title": "OpenVibe.Space API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tips API",
"title": "OpenVibe.Tips API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Today API",
"title": "OpenVibe.Today API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tools API",
"title": "OpenVibe.Tools API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Trade API",
"title": "OpenVibe.Trade API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.VIP API",
"title": "OpenVibe.VIP API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Vision API",
"title": "OpenVibe.Vision API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Watch API",
"title": "OpenVibe.Watch API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Wiki API",
"title": "OpenVibe.Wiki API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Work API",
"title": "OpenVibe.Work API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Zone API",
"title": "OpenVibe.Zone API",
- "version": "0.303.0",
- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.303.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.304.0",
+ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.304.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -294490,13 +294490,13 @@ export type ChatAgentPoll = {
@@ -294490,13 +294490,13 @@ export type ChatAgentPoll = {
/** [email protected] (owner: live) */
/** [email protected] (owner: live) */
/**
/**
- * live.agent-stream-control@1 (the Agent Streams plan, S5): one of the four controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. A moderator may press all four, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.
+ * live.agent-stream-control@1 (the Agent Streams plan, S5): one of the controls the owner and the channel's moderators have over a live agent stream, with who pressed it. PAUSE tells the task's service (Codes or Actor) to pause at the next safe point; the overlay then says 'Paused by @mod'. CURTAIN is the S1 curtain, raised from the viewer side. MUTE is the S4 mute: the agent voice stops. END ends the stream and the room's Co-pilot reading, while the task itself keeps running off camera unless it was paused. WIPE is the chat plays control of S6: it stops the run and resets the sandbox desk. A moderator may press every control, but may not resume a pause the owner set and may not change the mode or the task. Every press is logged: who, which control, when.
*/
*/
export interface LiveAgentStreamControl {
export interface LiveAgentStreamControl {
/**
/**
* Which control was pressed.
* Which control was pressed.
*/
*/
- control: "pause" | "curtain" | "mute" | "end";
+ control: "pause" | "curtain" | "mute" | "end" | "wipe";
/**
/**
* Who pressed it: the handle and the role they hold. Never an id, never anything else about them.
* Who pressed it: the handle and the role they hold. Never an id, never anything else about them.
*/
*/
@@ -294786,3 +294786,189 @@ export interface ChatTTSSpeakResult {
@@ -294786,3 +294786,189 @@ export interface ChatTTSSpeakResult {
rate?: number;
rate?: number;
voice_id?: string | null;
voice_id?: string | null;
}
}
+
+/** [email protected] (owner: chat) */
+/**
+ * chat.play-request@1 (the Agent Streams plan, S6): one viewer's request for the chat plays desk to build or do something. A request is written with `!do <request>` (at most 200 characters) in an agent stream's room, `agent:<ags_id>`. One open request per person at a time, and an account younger than a day cannot ask. The request passes the house text filters and the safety check before it is listed; a refused request carries a one-line reason and never enters the queue. Viewers vote with a thumbs-up or `!vote <n>`, and every five minutes, or when the current request finishes, the top request becomes the next task. The owner or a moderator can skip, remove or pin a request. The result is the run's outcome and the scratch site it left behind.
+ */
+export type ChatPlayRequest = {
+ [k: string]: unknown | undefined;
+} & {
+ /**
+ * The request's id (ULID, Crockford base32).
+ */
+ request_id: string;
+ /**
+ * The room the request was made in: an agent stream's room, `agent:<ags_id>`.
+ */
+ room: string;
+ /**
+ * Who asked. The handle and the display name only, never an id.
+ */
+ author: {
+ /**
+ * The handle of the person who asked.
+ */
+ handle: string;
+ /**
+ * Their display name, when they have one.
+ */
+ display_name?: string | null;
+ };
+ /**
+ * What the viewer asked for, as they typed it (at most 200 characters).
+ */
+ text: string;
+ /**
+ * How many votes the request has. The count says nothing about who voted.
+ */
+ votes: number;
+ /**
+ * How many people voted (one vote each).
+ */
+ voters?: number;
+ /**
+ * Where the request stands: queued (waiting), running (the desk is on it), done or failed (it ran), skipped (a moderator or the owner passed over it), removed (it left the queue) or refused (the safety check or the filters turned it down).
+ */
+ state: "queued" | "running" | "done" | "failed" | "skipped" | "removed" | "refused";
+ /**
+ * A pinned request stays at the top of the queue until it is removed or it runs.
+ */
+ pinned: boolean;
+ /**
+ * When the request was asked for.
+ */
+ created_at: string;
+ /**
+ * When the desk began it, or null while it waits.
+ */
+ started_at?: string | null;
+ /**
+ * When it finished, was skipped or was removed, or null while it stands.
+ */
+ ended_at?: string | null;
+ /**
+ * Why the request was refused, when it was: the code and the one-line reason the room saw. Null when the request was accepted.
+ */
+ refusal?: {
+ /**
+ * Which rule turned it down.
+ */
+ code: "platform_floor" | "harm" | "attack" | "account_or_money" | "account_too_new" | "too_long" | "already_open";
+ /**
+ * The one-line reason shown in the room.
+ */
+ reason: string;
+ } | null;
+ /**
+ * How the run ended, once it ran: the outcome and the line the overlay and the voice said.
+ */
+ result?: {
+ /**
+ * How it ended.
+ */
+ outcome: "done" | "failed" | "timeout" | "budget" | "stopped";
+ /**
+ * The one line the room and the overlay saw, e.g. 'Done: a snake game at the scratch address'.
+ */
+ line: string;
+ /**
+ * The throwaway scratch site the run left, when it left one.
+ */
+ scratch_url?: string | null;
+ /**
+ * The Codes task that ran it.
+ */
+ task_id?: string | null;
+ } | null;
+};
+
+/** [email protected] (owner: codes) */
+/**
+ * codes.sandbox-session@1 (the Agent Streams plan, S6): the sandbox desk a chat plays session runs on. The desk is started with `--shared`: no profile, no keys, no person's files, public egress only (no private address is reachable) and a fresh workspace, and it is wiped at the end of the session. The owner sets the time box (5 to 30 minutes) and the cap (money and minutes), and arms the session with Go before the first request may run. The scratch site is a throwaway OpenVibe.Space address that is removed after 24 hours unless the owner keeps it.
+ */
+export interface CodesSandboxSession {
+ /**
+ * The sandbox session's id (ULID, Crockford base32).
+ */
+ session_id: string;
+ /**
+ * The task the desk is running for the queue.
+ */
+ task: {
+ /**
+ * The task's id in Codes.
+ */
+ id: string;
+ title: string;
+ };
+ /**
+ * The person the session spends their own allowance for.
+ */
+ owner: string;
+ /**
+ * Where the desk stands: idle (nothing yet), armed (the owner pressed Go, the first request may run), running, paused, wiped (Wipe now reset the sandbox) or ended.
+ */
+ state: "idle" | "armed" | "running" | "paused" | "wiped" | "ended";
+ /**
+ * How long one request may run, in minutes (the owner sets 5 to 30; the default is 10).
+ */
+ time_box_minutes: number;
+ /**
+ * How many steps one request may take.
+ */
+ step_budget: number;
+ /**
+ * The owner's cap for the session: the money and the minutes it may spend. When it is spent, the queue closes.
+ */
+ cap: {
+ /**
+ * The cap in cents.
+ */
+ money_cents: number;
+ /**
+ * The cap in minutes of work.
+ */
+ minutes: number;
+ };
+ /**
+ * What the session has spent so far.
+ */
+ spend: {
+ money_cents: number;
+ seconds: number;
+ steps: number;
+ };
+ /**
+ * Whether the owner pressed Go. The first request of a session waits for it.
+ */
+ armed: boolean;
+ /**
+ * When the owner pressed Go.
+ */
+ armed_at?: string | null;
+ started_at?: string | null;
+ ended_at?: string | null;
+ /**
+ * When Wipe now reset the sandbox.
+ */
+ wiped_at?: string | null;
+ /**
+ * Always true: the sandbox reaches public addresses only, and no private address is reachable.
+ */
+ egress_public_only: true;
+ /**
+ * The throwaway site the run left, or null before the first one.
+ */
+ scratch_site?: {
+ url: string;
+ /**
+ * When it is removed (24 hours after it was made, unless it is kept).
+ */
+ expires_at: string;
+ /**
+ * Whether the owner kept it past its 24 hours.
+ */
+ kept: boolean;
+ } | null;
+}
@@ -6,7 +6,7 @@
@@ -6,7 +6,7 @@
const crypto = require('crypto');
const crypto = require('crypto');
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
-const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', consent: 'cns', job: 'job', task: 'tsk', watch: 'wch', wait: 'wai', observation: 'wco', check: 'ckr', subscription: 'sub', deploy: 'dpl', domain: 'dom', manifest: 'mfs', release: 'rel', site: 'sit', robot: 'rob', stream: 'std', webhook_delivery: 'whd', share: 'shr', device: 'dev', hook: 'hok', policy: 'pol', audit: 'aud' };
+const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', consent: 'cns', job: 'job', task: 'tsk', watch: 'wch', wait: 'wai', observation: 'wco', check: 'ckr', subscription: 'sub', deploy: 'dpl', domain: 'dom', manifest: 'mfs', release: 'rel', site: 'sit', robot: 'rob', stream: 'std', webhook_delivery: 'whd', share: 'shr', device: 'dev', hook: 'hok', policy: 'pol', audit: 'aud', agent_stream: 'ags', play_request: 'req', sandbox_session: 'sbs' };
const SLUG_TYPES = new Set(['service', 'system']);
const SLUG_TYPES = new Set(['service', 'system']);
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;
const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "chat.play_queue.read",
+ "version": "1.0",
+ "owner": "chat",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Read a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6). GET /internal/chat/rooms/agent:play-queue answers chat.play-request@1: the requests of the room `agent:<ags_id>`, each with its votes and its state, the current request and the top of the queue. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of), so the queue it reads is the owner's room and nobody else's. Chat chooses what the queue holds: a request enters it only after the house text filters and the safety check, one open request per person at a time.",
+ "inputSchema": "chat.play-request@1",
+ "outputSchema": "chat.play-request@1",
+ "permissions": [
+ "chat:read"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-read",
+ "events": [],
+ "implementedBy": [
+ "GET /internal/chat/rooms/agent:play-queue"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "chat.play_queue.write",
+ "version": "1.0",
+ "owner": "chat",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Write a chat plays queue on OpenVibe.Chat (the Agent Streams plan, S6): record how a request ran. POST /internal/chat/rooms/agent:play-queue/:request_id takes chat.play-request@1 and moves the request from queued to running, and records its outcome (done, failed, timeout, budget or stopped) with the one line the overlay and the voice say and the scratch site the run left. The caller is Codes, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never lets this capability ask for money, add a person to the queue or change a vote: the queue's people and votes belong to the room.",
+ "inputSchema": "chat.play-request@1",
+ "outputSchema": "chat.play-request@1",
+ "permissions": [
+ "chat:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-write",
+ "events": [],
+ "implementedBy": [
+ "POST /internal/chat/rooms/agent:play-queue/:request_id"
+ ]
+}
@@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
{
{
- "version": "0.4.0",
+ "version": "0.5.0",
"contractRanges": {
"contractRanges": {
"openvibe-contracts": ">=0.13.0 <1.0.0"
"openvibe-contracts": ">=0.13.0 <1.0.0"
},
},
@@ -21,6 +21,8 @@
@@ -21,6 +21,8 @@
"chat.inbox.read",
"chat.inbox.read",
"chat.inbox.reply",
"chat.inbox.reply",
"chat.live_bridge.write",
"chat.live_bridge.write",
+ "chat.play_queue.read",
+ "chat.play_queue.write",
"chat.message.send",
"chat.message.send",
"chat.messages.read",
"chat.messages.read",
"chat.moderation.queue.read",
"chat.moderation.queue.read",
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.302.0",
+ "version": "0.304.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.302.0",
+ "version": "0.304.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.303.0",
+ "version": "0.304.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",