openvibers/openvibe.contracts Commits
Agent Streams S5: the digest, the poll and the four controls (0.303.0) (#313)
Changes
@@@ -1,5 +1,15 @@# Changelog++## 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-poll@1`: the poll an agent asks a Co-pilot room to run, and the result it gets back — the question and the two to four options the agent wrote, the window it is open for, the state (`open`, `closed` or `vetoed`) and the counts. An open poll carries no result, a closed one carries its counts and its winner, a vetoed one names who refused it.++- Add `live.agent-stream-control@1`: one of the four controls the owner and the channel's moderators have over a live agent stream — `pause`, `curtain`, `mute` or `end` — with who pressed it (the handle and the role: owner or moderator) and when, and whose pause is in force.++- Add the capabilities `chat.agent_digest.read` and `chat.agent_poll.write` (first-party), and name both in Chat's service manifest. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token `on_behalf_of`), so a digest is the owner's room and nobody else's.++- `chat.preferences` is v2: it gains `agents_read_messages` ('Agents don't read my messages'). A v1 record upgrades with it true — joining a Co-pilot room and writing in it is the choice, and the person can take it back.++- `live.agent_stream.publish` now names the controls (`POST /api/streams/agent/:id/control`, `GET /api/streams/agent/:id/controls`) and the step credit: a step may name the suggestion it took.++- Additive: nothing that exists changes. Fixtures cover a digest over the ten-item cap, an unknown kind, a room that is not an agent room, a poll with one option and with five, an open poll carrying a result, an unknown control, a control with nobody behind it and a role that is neither owner nor moderator.++## 0.302.0 — 2026-11-06- Add the capabilities `media.avatar.adopt` and `media.avatar.release` (internal), and name both in Media's service manifest. After the 2026-11-06 incident (eleven avatars were soft-deleted with the public screenshot copies), Media records which avatar object each profile slot points at, and its delete refuses an object a working profile still shows. A product (Network for `users.avatar_url`, Live for its own copy and the channel banner) records a slot with `POST /internal/avatar-adopt` and drops it with `POST /internal/avatar-release`.@@@ -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.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)","45 service manifests with lifecycle declarations (39 alpha, 1 beta, 4 stable, 1 retired)","348 capability manifests (306 active, 27 planned, 15 retired) and the staff capability map",@@@ -36,11 +38,11 @@"OpenVibe.Food, OpenVibe.Help and OpenVibe.Work become services (plan T19); OpenVibe.Quest and OpenVibe.Rent become services","the forum returns to Community; Deals goes live, with product copy for the new sites","OpenVibe.MediaHub goes live (openvibe.download as a private drive); services declare the account events they consume (ADR-033, SDK 0.37.0)",-- "ADR-054 — the OpenVibe inventory authority (kinds, definitions, instances, equipped and the ledger), its planned service, capabilities, schemas and events (plan T21 step 1)",++ "ADR-054 \u2014 the OpenVibe inventory authority (kinds, definitions, instances, equipped and the ledger), its planned service, capabilities, schemas and events (plan T21 step 1)","OpenVibe.Inventory goes live (inventory.openvibe.network, site position 30) with six capabilities active (ADR-054, plan T21 step 2); a definition may name the services or apps that may grant it","the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots","News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)",-- "ADR-055 (proposed): money and the inventory — primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",++ "ADR-055 (proposed): money and the inventory \u2014 primary sales first, gifting next; trading and a market stay closed, and chance is never paid for","bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)"],"updated": "2026-10-30"@@@ -9511,6 +9511,33 @@"compatibility": "backward","status": "active"},++ {++ "id": "chat.agent-digest",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/agent-digest.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "chat.agent-poll",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/agent-poll.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent-stream-control",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream-control.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },{"id": "live.agent_stream.changed","version": "1.0.0",nnew file mode 100644@@@ -0,0 +1,105 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/agent-digest.v1.json",++ "title": "ChatAgentDigest",++ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "room",++ "since",++ "until",++ "items"++ ],++ "properties": {++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "The start of the window: the moment the agent last read, or null for the first read."++ },++ "until": {++ "type": "string",++ "format": "date-time",++ "description": "The end of the window: the moment this digest was made."++ },++ "items": {++ "type": "array",++ "maxItems": 10,++ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "who",++ "what",++ "kind",++ "upvotes"++ ],++ "properties": {++ "who": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "display_name",++ "handle"++ ],++ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",++ "properties": {++ "display_name": {++ "type": "string",++ "maxLength": 80,++ "description": "The name the room shows."++ },++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle, so the agent can answer this person by name."++ }++ }++ },++ "what": {++ "type": "string",++ "maxLength": 200,++ "description": "What they said, cut to 200 characters. A link is kept as its domain only."++ },++ "kind": {++ "enum": [++ "question",++ "suggestion",++ "reaction"++ ],++ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."++ },++ "upvotes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many thumbs up the message carries. The most-upvoted items come first."++ },++ "repeated": {++ "type": "integer",++ "minimum": 1,++ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."++ }++ }++ }++ },++ "chars": {++ "type": "integer",++ "minimum": 0,++ "maximum": 1500,++ "description": "How many characters the items use together, at most 1,500."++ },++ "truncated": {++ "type": "boolean",++ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,221 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/agent-poll.v1.json",++ "title": "ChatAgentPoll",++ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "poll_id",++ "room",++ "question",++ "options",++ "opened_at",++ "closes_at",++ "state"++ ],++ "properties": {++ "poll_id": {++ "type": "string",++ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The poll's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."++ },++ "question": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The question the agent wrote."++ },++ "options": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^[1-4]$",++ "description": "The option's number: `!1` to `!4` vote for it."++ },++ "label": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80,++ "description": "The option's text, as the agent wrote it."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people chose it. The count is in the result; it says nothing about who."++ }++ }++ }++ },++ "opened_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll opened."++ },++ "closes_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."++ },++ "closed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."++ },++ "state": {++ "enum": [++ "open",++ "closed",++ "vetoed"++ ],++ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",++ "required": [++ "counts",++ "total"++ ],++ "properties": {++ "counts": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "How many votes each option got, in the order the options were written.",++ "items": {++ "type": "integer",++ "minimum": 0++ }++ },++ "total": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted."++ },++ "winner": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^[1-4]$",++ "description": "The option that won, or null when there was no vote or no winner."++ }++ }++ },++ "vetoed_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "open"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "result": {++ "type": "null"++ },++ "closed_at": {++ "type": "null"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "closed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "result"++ ],++ "properties": {++ "result": {++ "type": "object"++ },++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "vetoed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "vetoed_by"++ ],++ "properties": {++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "string"++ }++ }++ }++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,64 @@++{++ "$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.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "control",++ "by",++ "at"++ ],++ "properties": {++ "control": {++ "enum": [++ "pause",++ "curtain",++ "mute",++ "end"++ ],++ "description": "Which control was pressed."++ },++ "by": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle",++ "role"++ ],++ "description": "Who pressed it: the handle and the role they hold. Never an id, never anything else about them.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who pressed the control."++ },++ "role": {++ "enum": [++ "owner",++ "moderator"++ ],++ "description": "What they are on this stream: the owner, or one of the channel's moderators."++ }++ }++ },++ "at": {++ "type": "string",++ "format": "date-time",++ "description": "When the control was pressed."++ },++ "stream": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent stream the control was pressed on."++ },++ "paused_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,106 @@++{++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "since": null,++ "until": "2026-11-06T10:05:00.000Z",++ "items": [++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ },++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "reaction",++ "upvotes": 0++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "room": "chat:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "since": null,++ "until": "2026-11-06T10:05:00.000Z",++ "items": []++}nnew file mode 100644@@@ -0,0 +1,16 @@++{++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "since": null,++ "until": "2026-11-06T10:05:00.000Z",++ "items": [++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "hi",++ "kind": "greeting",++ "upvotes": 0++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "since": null,++ "until": "2026-11-06T10:05:00.000Z",++ "chars": 0,++ "truncated": false,++ "items": []++}nnew file mode 100644@@@ -0,0 +1,28 @@++{++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "since": "2026-11-06T10:00:00.000Z",++ "until": "2026-11-06T10:05:00.000Z",++ "chars": 120,++ "truncated": false,++ "items": [++ {++ "who": {++ "display_name": "Mira",++ "handle": "mira"++ },++ "what": "why is the test flaky?",++ "kind": "question",++ "upvotes": 3++ },++ {++ "who": {++ "display_name": "Sam",++ "handle": "sam"++ },++ "what": "a link to github.com",++ "kind": "suggestion",++ "upvotes": 2,++ "repeated": 2++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,35 @@++{++ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "question": "Which name?",++ "options": [++ {++ "id": "1",++ "label": "a",++ "votes": 0++ },++ {++ "id": "2",++ "label": "b",++ "votes": 0++ },++ {++ "id": "3",++ "label": "c",++ "votes": 0++ },++ {++ "id": "4",++ "label": "d",++ "votes": 0++ },++ {++ "id": "5",++ "label": "e",++ "votes": 0++ }++ ],++ "opened_at": "2026-11-06T10:00:00.000Z",++ "closes_at": "2026-11-06T10:01:00.000Z",++ "state": "open"++}nnew file mode 100644@@@ -0,0 +1,15 @@++{++ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "question": "Which name?",++ "options": [++ {++ "id": "1",++ "label": "parseRows",++ "votes": 0++ }++ ],++ "opened_at": "2026-11-06T10:00:00.000Z",++ "closes_at": "2026-11-06T10:01:00.000Z",++ "state": "open"++}nnew file mode 100644@@@ -0,0 +1,28 @@++{++ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "question": "Which name?",++ "options": [++ {++ "id": "1",++ "label": "a",++ "votes": 0++ },++ {++ "id": "2",++ "label": "b",++ "votes": 0++ }++ ],++ "opened_at": "2026-11-06T10:00:00.000Z",++ "closes_at": "2026-11-06T10:01:00.000Z",++ "state": "open",++ "result": {++ "counts": [++ 1,++ 0++ ],++ "total": 1,++ "winner": "1"++ }++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "question": "Which name: parseRows or readTable?",++ "options": [++ {++ "id": "1",++ "label": "parseRows",++ "votes": 4++ },++ {++ "id": "2",++ "label": "readTable",++ "votes": 1++ }++ ],++ "opened_at": "2026-11-06T10:00:00.000Z",++ "closes_at": "2026-11-06T10:01:00.000Z",++ "closed_at": "2026-11-06T10:01:00.000Z",++ "state": "closed",++ "result": {++ "counts": [++ 4,++ 1++ ],++ "total": 5,++ "winner": "1"++ },++ "vetoed_by": null++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "question": "Which name: parseRows or readTable?",++ "options": [++ {++ "id": "1",++ "label": "parseRows",++ "votes": 0++ },++ {++ "id": "2",++ "label": "readTable",++ "votes": 0++ }++ ],++ "opened_at": "2026-11-06T10:00:00.000Z",++ "closes_at": "2026-11-06T10:01:00.000Z",++ "closed_at": null,++ "state": "open",++ "result": null,++ "vetoed_by": null++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "control": "pause",++ "at": "2026-11-06T10:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "control": "pause",++ "by": {++ "handle": "mod",++ "role": "viewer"++ },++ "at": "2026-11-06T10:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "control": "nuke",++ "by": {++ "handle": "mod",++ "role": "moderator"++ },++ "at": "2026-11-06T10:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "control": "end",++ "by": {++ "handle": "owner",++ "role": "owner"++ },++ "at": "2026-11-06T10:00:00.000Z",++ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "paused_by": null++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "control": "pause",++ "by": {++ "handle": "mod",++ "role": "moderator"++ },++ "at": "2026-11-06T10:00:00.000Z",++ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "paused_by": "mod"++}@@@ -104271,6 +104271,411 @@}}},++ "chat.agent-digest": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/agent-digest.v1.json",++ "title": "ChatAgentDigest",++ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "room",++ "since",++ "until",++ "items"++ ],++ "properties": {++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "The start of the window: the moment the agent last read, or null for the first read."++ },++ "until": {++ "type": "string",++ "format": "date-time",++ "description": "The end of the window: the moment this digest was made."++ },++ "items": {++ "type": "array",++ "maxItems": 10,++ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "who",++ "what",++ "kind",++ "upvotes"++ ],++ "properties": {++ "who": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "display_name",++ "handle"++ ],++ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",++ "properties": {++ "display_name": {++ "type": "string",++ "maxLength": 80,++ "description": "The name the room shows."++ },++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle, so the agent can answer this person by name."++ }++ }++ },++ "what": {++ "type": "string",++ "maxLength": 200,++ "description": "What they said, cut to 200 characters. A link is kept as its domain only."++ },++ "kind": {++ "enum": [++ "question",++ "suggestion",++ "reaction"++ ],++ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."++ },++ "upvotes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many thumbs up the message carries. The most-upvoted items come first."++ },++ "repeated": {++ "type": "integer",++ "minimum": 1,++ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."++ }++ }++ }++ },++ "chars": {++ "type": "integer",++ "minimum": 0,++ "maximum": 1500,++ "description": "How many characters the items use together, at most 1,500."++ },++ "truncated": {++ "type": "boolean",++ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."++ }++ }++ }++ },++ "chat.agent-poll": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/agent-poll.v1.json",++ "title": "ChatAgentPoll",++ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "poll_id",++ "room",++ "question",++ "options",++ "opened_at",++ "closes_at",++ "state"++ ],++ "properties": {++ "poll_id": {++ "type": "string",++ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The poll's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."++ },++ "question": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The question the agent wrote."++ },++ "options": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^[1-4]$",++ "description": "The option's number: `!1` to `!4` vote for it."++ },++ "label": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80,++ "description": "The option's text, as the agent wrote it."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people chose it. The count is in the result; it says nothing about who."++ }++ }++ }++ },++ "opened_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll opened."++ },++ "closes_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."++ },++ "closed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."++ },++ "state": {++ "enum": [++ "open",++ "closed",++ "vetoed"++ ],++ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",++ "required": [++ "counts",++ "total"++ ],++ "properties": {++ "counts": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "How many votes each option got, in the order the options were written.",++ "items": {++ "type": "integer",++ "minimum": 0++ }++ },++ "total": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted."++ },++ "winner": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^[1-4]$",++ "description": "The option that won, or null when there was no vote or no winner."++ }++ }++ },++ "vetoed_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "open"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "result": {++ "type": "null"++ },++ "closed_at": {++ "type": "null"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "closed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "result"++ ],++ "properties": {++ "result": {++ "type": "object"++ },++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "vetoed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "vetoed_by"++ ],++ "properties": {++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "string"++ }++ }++ }++ }++ ]++ }++ },++ "live.agent-stream-control": {++ "version": "1.0.0",++ "owner": "live",++ "status": "active",++ "schema": {++ "$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.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "control",++ "by",++ "at"++ ],++ "properties": {++ "control": {++ "enum": [++ "pause",++ "curtain",++ "mute",++ "end"++ ],++ "description": "Which control was pressed."++ },++ "by": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "handle",++ "role"++ ],++ "description": "Who pressed it: the handle and the role they hold. Never an id, never anything else about them.",++ "properties": {++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle of the person who pressed the control."++ },++ "role": {++ "enum": [++ "owner",++ "moderator"++ ],++ "description": "What they are on this stream: the owner, or one of the channel's moderators."++ }++ }++ },++ "at": {++ "type": "string",++ "format": "date-time",++ "description": "When the control was pressed."++ },++ "stream": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent stream the control was pressed on."++ },++ "paused_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is."++ }++ }++ }++ },"live.agent_stream.changed": {"version": "1.0.0","owner": "live",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.302.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","license": {"name": "MIT","identifier": "MIT"@@@ -3709,6 +3709,491 @@}}},++ "/internal/chat/rooms/agent{digest}": {++ "get": {++ "operationId": "get_internal_chat_rooms_agentdigest",++ "summary": "Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5).",++ "description": "**chat.agent_digest.read** (first-party): Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5). GET /internal/chat/rooms/agent:digest?since= answers chat.agent-digest@1: at most ten items and 1,500 characters, each with who (the display name and the handle), what (cut to 200 characters), its kind (a question, a suggestion or a reaction) and its upvotes. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of), so the digest is the owner's room and nobody else's. Chat chooses what goes in 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' is never in the digest, and a link is kept as its domain only. The agent never reads the raw room, and one read per step at most, twenty seconds apart.",++ "tags": [++ "chat.agent_digest"++ ],++ "x-openvibe-capabilities": [++ "chat.agent_digest.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-read",++ "security": [++ {++ "openvibeToken": [++ "chat.agent_digest.read"++ ]++ }++ ],++ "x-openvibe-input": {++ "$ref": "#/components/schemas/chat.agent-digest.v1"++ },++ "parameters": [++ {++ "name": "digest",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "room",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."++ },++ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."++ },++ {++ "name": "since",++ "in": "query",++ "required": true,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "The start of the window: the moment the agent last read, or null for the first read."++ },++ "description": "The start of the window: the moment the agent last read, or null for the first read."++ },++ {++ "name": "until",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "format": "date-time",++ "description": "The end of the window: the moment this digest was made."++ },++ "description": "The end of the window: the moment this digest was made."++ },++ {++ "name": "items",++ "in": "query",++ "required": true,++ "schema": {++ "type": "array",++ "maxItems": 10,++ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "who",++ "what",++ "kind",++ "upvotes"++ ],++ "properties": {++ "who": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "display_name",++ "handle"++ ],++ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",++ "properties": {++ "display_name": {++ "type": "string",++ "maxLength": 80,++ "description": "The name the room shows."++ },++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle, so the agent can answer this person by name."++ }++ }++ },++ "what": {++ "type": "string",++ "maxLength": 200,++ "description": "What they said, cut to 200 characters. A link is kept as its domain only."++ },++ "kind": {++ "enum": [++ "question",++ "suggestion",++ "reaction"++ ],++ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."++ },++ "upvotes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many thumbs up the message carries. The most-upvoted items come first."++ },++ "repeated": {++ "type": "integer",++ "minimum": 1,++ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."++ }++ }++ }++ },++ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last."++ },++ {++ "name": "chars",++ "in": "query",++ "required": false,++ "schema": {++ "type": "integer",++ "minimum": 0,++ "maximum": 1500,++ "description": "How many characters the items use together, at most 1,500."++ },++ "description": "How many characters the items use together, at most 1,500."++ },++ {++ "name": "truncated",++ "in": "query",++ "required": false,++ "schema": {++ "type": "boolean",++ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."++ },++ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.agent-digest.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",++ "summary": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5).",++ "description": "**chat.agent_poll.write** (first-party): Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",++ "tags": [++ "chat.agent_poll"++ ],++ "x-openvibe-capabilities": [++ "chat.agent_poll.write"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-write",++ "security": [++ {++ "openvibeToken": [++ "chat.agent_poll.write"++ ]++ }++ ],++ "x-openvibe-input": {++ "$ref": "#/components/schemas/chat.agent-poll.v1"++ },++ "parameters": [++ {++ "name": "poll",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "poll_id",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The poll's id (ULID, Crockford base32)."++ },++ "description": "The poll'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 poll is in: an agent stream's room, `agent:<ags_id>`."++ },++ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."++ },++ {++ "name": "question",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The question the agent wrote."++ },++ "description": "The question the agent wrote."++ },++ {++ "name": "options",++ "in": "query",++ "required": true,++ "schema": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^[1-4]$",++ "description": "The option's number: `!1` to `!4` vote for it."++ },++ "label": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80,++ "description": "The option's text, as the agent wrote it."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people chose it. The count is in the result; it says nothing about who."++ }++ }++ }++ },++ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own."++ },++ {++ "name": "opened_at",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll opened."++ },++ "description": "When the poll opened."++ },++ {++ "name": "closes_at",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."++ },++ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."++ },++ {++ "name": "closed_at",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."++ },++ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."++ },++ {++ "name": "state",++ "in": "query",++ "required": true,++ "schema": {++ "enum": [++ "open",++ "closed",++ "vetoed"++ ],++ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."++ },++ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."++ },++ {++ "name": "result",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",++ "required": [++ "counts",++ "total"++ ],++ "properties": {++ "counts": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "How many votes each option got, in the order the options were written.",++ "items": {++ "type": "integer",++ "minimum": 0++ }++ },++ "total": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted."++ },++ "winner": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^[1-4]$",++ "description": "The option that won, or null when there was no vote or no winner."++ }++ }++ },++ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open."++ },++ {++ "name": "vetoed_by",++ "in": "query",++ "required": false,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."++ },++ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.agent-poll.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ },++ "post": {++ "operationId": "post_internal_chat_rooms_agentpoll",++ "summary": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5).",++ "description": "**chat.agent_poll.write** (first-party): Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",++ "tags": [++ "chat.agent_poll"++ ],++ "x-openvibe-capabilities": [++ "chat.agent_poll.write"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-write",++ "security": [++ {++ "openvibeToken": [++ "chat.agent_poll.write"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.agent-poll.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "poll",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.agent-poll.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/internal/chat/sounds": {"get": {"operationId": "get_internal_chat_sounds",@@@ -4478,6 +4963,328 @@},"components": {"schemas": {++ "chat.agent-digest.v1": {++ "title": "ChatAgentDigest",++ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "room",++ "since",++ "until",++ "items"++ ],++ "properties": {++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "The start of the window: the moment the agent last read, or null for the first read."++ },++ "until": {++ "type": "string",++ "format": "date-time",++ "description": "The end of the window: the moment this digest was made."++ },++ "items": {++ "type": "array",++ "maxItems": 10,++ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "who",++ "what",++ "kind",++ "upvotes"++ ],++ "properties": {++ "who": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "display_name",++ "handle"++ ],++ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",++ "properties": {++ "display_name": {++ "type": "string",++ "maxLength": 80,++ "description": "The name the room shows."++ },++ "handle": {++ "type": "string",++ "pattern": "^[a-z0-9_]{2,32}$",++ "description": "The handle, so the agent can answer this person by name."++ }++ }++ },++ "what": {++ "type": "string",++ "maxLength": 200,++ "description": "What they said, cut to 200 characters. A link is kept as its domain only."++ },++ "kind": {++ "enum": [++ "question",++ "suggestion",++ "reaction"++ ],++ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."++ },++ "upvotes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many thumbs up the message carries. The most-upvoted items come first."++ },++ "repeated": {++ "type": "integer",++ "minimum": 1,++ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."++ }++ }++ }++ },++ "chars": {++ "type": "integer",++ "minimum": 0,++ "maximum": 1500,++ "description": "How many characters the items use together, at most 1,500."++ },++ "truncated": {++ "type": "boolean",++ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."++ }++ }++ },++ "chat.agent-poll.v1": {++ "title": "ChatAgentPoll",++ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "poll_id",++ "room",++ "question",++ "options",++ "opened_at",++ "closes_at",++ "state"++ ],++ "properties": {++ "poll_id": {++ "type": "string",++ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The poll's id (ULID, Crockford base32)."++ },++ "room": {++ "type": "string",++ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."++ },++ "question": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The question the agent wrote."++ },++ "options": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^[1-4]$",++ "description": "The option's number: `!1` to `!4` vote for it."++ },++ "label": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80,++ "description": "The option's text, as the agent wrote it."++ },++ "votes": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people chose it. The count is in the result; it says nothing about who."++ }++ }++ }++ },++ "opened_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll opened."++ },++ "closes_at": {++ "type": "string",++ "format": "date-time",++ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."++ },++ "closed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."++ },++ "state": {++ "enum": [++ "open",++ "closed",++ "vetoed"++ ],++ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."++ },++ "result": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",++ "required": [++ "counts",++ "total"++ ],++ "properties": {++ "counts": {++ "type": "array",++ "minItems": 2,++ "maxItems": 4,++ "description": "How many votes each option got, in the order the options were written.",++ "items": {++ "type": "integer",++ "minimum": 0++ }++ },++ "total": {++ "type": "integer",++ "minimum": 0,++ "description": "How many people voted."++ },++ "winner": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^[1-4]$",++ "description": "The option that won, or null when there was no vote or no winner."++ }++ }++ },++ "vetoed_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."++ }++ },++ "allOf": [++ {++ "if": {++ "properties": {++ "state": {++ "const": "open"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "properties": {++ "result": {++ "type": "null"++ },++ "closed_at": {++ "type": "null"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "closed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "result"++ ],++ "properties": {++ "result": {++ "type": "object"++ },++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "null"++ }++ }++ }++ },++ {++ "if": {++ "properties": {++ "state": {++ "const": "vetoed"++ }++ },++ "required": [++ "state"++ ]++ },++ "then": {++ "required": [++ "closed_at",++ "vetoed_by"++ ],++ "properties": {++ "closed_at": {++ "type": "string",++ "format": "date-time"++ },++ "vetoed_by": {++ "type": "string"++ }++ }++ }++ }++ ]++ },"chat.channel-moderation-result.v1": {"title": "ChatChannelModerationResult","description": "chat.channel-moderation-result@1: the answer of GET /internal/moderation/channels/:channelId on OpenVibe.Chat (capability chat.moderation.read): { ok: true, settings, moderator_ids } — one channel's moderation settings and the ids of the people who moderate it, for OpenVibe.Live's stream chat. settings carries every channel_moderation_settings column (Live's own defaults when the channel has no row yet, database.js getChannelModerationSettings); the switches are 0/1 as the table stores them. moderator_ids are Live user ids (channel_moderators.user_id), never names. A failure is { ok: false, error }; a caller without the grant gets 401 { ok: false }.",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.302.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","license": {"name": "MIT","identifier": "MIT"@@@ -47,8 +47,8 @@"service": "chat","name": "OpenVibe.Chat","origin": "https://openvibe.chat",-- "operations": 55,-- "capabilities": 20++ "operations": 58,++ "capabilities": 22},{"service": "codes",@@@ -124,7 +124,7 @@"service": "live","name": "OpenVibe.Live","origin": "https://openvibe.live",-- "operations": 38,++ "operations": 40,"capabilities": 11},{@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Inventory API",-- "version": "0.302.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","license": {"name": "MIT","identifier": "MIT"@@@ -694,7 +694,7 @@"post": {"operationId": "post_api_streams_agent","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -746,11 +746,181 @@}}},++ "/api/streams/agent/{id}/control": {++ "post": {++ "operationId": "post_api_streams_agent_id_control",++ "summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "tags": [++ "live.agent_stream"++ ],++ "x-openvibe-capabilities": [++ "live.agent_stream.publish"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "standard",++ "security": [++ {++ "openvibeToken": [++ "live.agent_stream.publish"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/live.agent-stream-create-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/live.agent-stream-publish.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/streams/agent/{id}/controls": {++ "get": {++ "operationId": "get_api_streams_agent_id_controls",++ "summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "tags": [++ "live.agent_stream"++ ],++ "x-openvibe-capabilities": [++ "live.agent_stream.publish"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "standard",++ "security": [++ {++ "openvibeToken": [++ "live.agent_stream.publish"++ ]++ }++ ],++ "x-openvibe-input": {++ "$ref": "#/components/schemas/live.agent-stream-create-request.v1"++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "title",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ }++ },++ {++ "name": "task",++ "in": "query",++ "required": true,++ "schema": {++ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"++ }++ },++ {++ "name": "visibility",++ "in": "query",++ "required": true,++ "schema": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ }++ },++ {++ "name": "allow_sites",++ "in": "query",++ "required": false,++ "schema": {++ "type": "array",++ "maxItems": 50,++ "items": {++ "type": "string",++ "format": "uri"++ },++ "description": "The hosts the browser desk may visit. Absent means no limit."++ },++ "description": "The hosts the browser desk may visit. Absent means no limit."++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/live.agent-stream-publish.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/api/streams/agent/{id}/curtain": {"post": {"operationId": "post_api_streams_agent_id_curtain","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -816,7 +986,7 @@"post": {"operationId": "post_api_streams_agent_id_end","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -882,7 +1052,7 @@"put": {"operationId": "put_api_streams_agent_id_frame","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -948,7 +1118,7 @@"get": {"operationId": "get_api_streams_agent_id_state","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -1052,7 +1222,7 @@"delete": {"operationId": "delete_api_streams_agent_id_ticket","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -1154,7 +1324,7 @@"post": {"operationId": "post_api_streams_agent_id_ticket","summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",-- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","tags": ["live.agent_stream"],@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.MediaHub API",-- "version": "0.302.0",-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRestream API",-- "version": "0.302.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","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.302.0",-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.","license": {"name": "MIT","identifier": "MIT"@@@ -292529,6 +292529,2001 @@ export interface LiveAgentStreamStepRequest {cost_usd?: number;}++/** [email protected] (owner: chat) */++/**++ * chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.++ */++export interface ChatAgentDigest {++ /**++ * The room the digest came from: an agent stream's room, `agent:<ags_id>`.++ */++ room: string;++ /**++ * The start of the window: the moment the agent last read, or null for the first read.++ */++ since: string | null;++ /**++ * The end of the window: the moment this digest was made.++ */++ until: string;++ /**++ * What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.++ *++ * @maxItems 10++ */++ items:++ | []++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ]++ | [++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ },++ {++ /**++ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.++ */++ who: {++ /**++ * The name the room shows.++ */++ display_name: string;++ /**++ * The handle, so the agent can answer this person by name.++ */++ handle: string;++ };++ /**++ * What they said, cut to 200 characters. A link is kept as its domain only.++ */++ what: string;++ /**++ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.++ */++ kind: "question" | "suggestion" | "reaction";++ /**++ * How many thumbs up the message carries. The most-upvoted items come first.++ */++ upvotes: number;++ /**++ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.++ */++ repeated?: number;++ }++ ];++ /**++ * How many characters the items use together, at most 1,500.++ */++ chars?: number;++ /**++ * True when Chat left something out because of the ten-item or 1,500-character cap.++ */++ truncated?: boolean;++}++++/** [email protected] (owner: chat) */++/**++ * chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.++ */++export type ChatAgentPoll = {++ [k: string]: unknown | undefined;++} & {++ /**++ * The poll's id (ULID, Crockford base32).++ */++ poll_id: string;++ /**++ * The room the poll is in: an agent stream's room, `agent:<ags_id>`.++ */++ room: string;++ /**++ * The question the agent wrote.++ */++ question: string;++ /**++ * The options the agent wrote, two to four of them. Chat never adds an option of its own.++ *++ * @minItems 2++ * @maxItems 4++ */++ options:++ | [++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ }++ ]++ | [++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ }++ ]++ | [++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ },++ {++ /**++ * The option's number: `!1` to `!4` vote for it.++ */++ id: string;++ /**++ * The option's text, as the agent wrote it.++ */++ label: string;++ /**++ * How many people chose it. The count is in the result; it says nothing about who.++ */++ votes?: number;++ }++ ];++ /**++ * When the poll opened.++ */++ opened_at: string;++ /**++ * When the poll closes on its own: 30 to 120 seconds after it opened.++ */++ closes_at: string;++ /**++ * When the poll was closed early by the owner or a moderator, or null when it ran its time.++ */++ closed_at?: string | null;++ /**++ * Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result).++ */++ state: "open" | "closed" | "vetoed";++ /**++ * The result, once the poll is closed: the counts and the winning option. Null while the poll is open.++ */++ result?: {++ /**++ * How many votes each option got, in the order the options were written.++ *++ * @minItems 2++ * @maxItems 4++ */++ counts: [number, number] | [number, number, number] | [number, number, number, number];++ /**++ * How many people voted.++ */++ total: number;++ /**++ * The option that won, or null when there was no vote or no winner.++ */++ winner?: string | null;++ } | null;++ /**++ * Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only.++ */++ vetoed_by?: string | null;++};++++/** [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.++ */++export interface LiveAgentStreamControl {++ /**++ * Which control was pressed.++ */++ control: "pause" | "curtain" | "mute" | "end";++ /**++ * Who pressed it: the handle and the role they hold. Never an id, never anything else about them.++ */++ by: {++ /**++ * The handle of the person who pressed the control.++ */++ handle: string;++ /**++ * What they are on this stream: the owner, or one of the channel's moderators.++ */++ role: "owner" | "moderator";++ };++ /**++ * When the control was pressed.++ */++ at: string;++ /**++ * The agent stream the control was pressed on.++ */++ stream?: string;++ /**++ * The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is.++ */++ paused_by?: string | null;++}++/** [email protected] (owner: live) *//*** live.agent_stream.changed v1 (OpenVibe.Live, the Agent Streams plan, S1): an agent stream changed. KIND is what happened: started, ended, visibility (the owner switched it) or curtain (the desk's privacy screen went up or came down). It says what happened and never why: the curtain's reason stays with the owner, so a subscriber learns that a private screen is up, not that a password field was focused. VISIBILITY carries the new visibility when KIND is visibility, CURTAIN whether the screen is up when KIND is curtain. The publish ticket, the stream key and the task's contents never appear. Envelope: subject { type: agent_stream, id: ags_… }, actor the owner's subject when Live knows it, else service:live. The event type carries no hyphen (events.event-envelope@1's event_type pattern allows letters, digits and underscores only), so it is live.agent_stream.changed; the stream's contract ids keep live.agent-stream@1.nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "chat.agent_digest.read",++ "version": "1.0",++ "owner": "chat",++ "status": "active",++ "visibility": "first-party",++ "description": "Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5). GET /internal/chat/rooms/agent:digest?since= answers chat.agent-digest@1: at most ten items and 1,500 characters, each with who (the display name and the handle), what (cut to 200 characters), its kind (a question, a suggestion or a reaction) and its upvotes. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of), so the digest is the owner's room and nobody else's. Chat chooses what goes in 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' is never in the digest, and a link is kept as its domain only. The agent never reads the raw room, and one read per step at most, twenty seconds apart.",++ "permissions": [++ "chat:read"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-read",++ "events": [],++ "implementedBy": [++ "GET /internal/chat/rooms/agent:digest"++ ],++ "inputSchema": "chat.agent-digest@1",++ "outputSchema": "chat.agent-digest@1"++}nnew file mode 100644@@@ -0,0 +1,22 @@++{++ "id": "chat.agent_poll.write",++ "version": "1.0",++ "owner": "chat",++ "status": "active",++ "visibility": "first-party",++ "description": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",++ "permissions": [++ "chat:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-write",++ "events": [],++ "implementedBy": [++ "POST /internal/chat/rooms/agent:poll",++ "GET /internal/chat/rooms/agent:poll"++ ],++ "inputSchema": "chat.agent-poll@1",++ "outputSchema": "chat.agent-poll@1"++}@@@ -4,7 +4,7 @@"owner": "live","status": "active","visibility": "public",-- "description": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",++ "description": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.","inputSchema": "live.agent-stream-create-request@1","outputSchema": "live.agent-stream-publish@1","permissions": [@@@ -24,7 +24,9 @@"POST /api/streams/agent/:id/curtain","PUT /api/streams/agent/:id/frame","POST /api/streams/agent/:id/end",-- "GET /api/streams/agent/:id/state"++ "GET /api/streams/agent/:id/state",++ "POST /api/streams/agent/:id/control",++ "GET /api/streams/agent/:id/controls"],"sensitive": true}@@@ -1,8 +1,9 @@{"namespace": "chat.preferences","owner": "chat",-- "version": 1,-- "description": "How chat looks for this person on every site with OpenVibe chat: timestamps, compact messages, text size, badges and emotes.",++ "version": 2,++ "migration": "v2 adds agents_read_messages (the Agent Streams plan, S5: 'Agents don't read my messages'). A v1 record upgrades to a v2 record that reads true: joining a Co-pilot room and writing in it is the choice, and the person can take it back.",++ "description": "How chat looks for this person on every site with OpenVibe chat: timestamps, compact messages, text size, badges and emotes, and whether an AI agent may read their messages (the Co-pilot rooms of the Agent Streams plan, S5).","writers": ["owner","user"@@@ -30,7 +31,20 @@},"hide_emotes": {"type": "boolean"++ },++ "agents_read_messages": {++ "type": "boolean",++ "description": "Whether an AI agent may read this person's chat messages. True by default: joining a Co-pilot room and writing in it is the choice, and it can be taken back. When false the digest leaves this person out entirely."++ }++ }++ },++ "migrations": [++ {++ "from": 1,++ "to": 2,++ "defaults": {++ "agents_read_messages": true}}-- }++ ]}@@@ -12,6 +12,8 @@],"publicOrigin": "https://openvibe.chat","capabilities": [++ "chat.agent_digest.read",++ "chat.agent_poll.write","chat.analysis.read","chat.cache.invalidate","chat.event.publish",@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.301.0",++ "version": "0.302.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.301.0",++ "version": "0.302.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.302.0",++ "version": "0.303.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,15 @@
@@ -1,5 +1,15 @@
# Changelog
# Changelog
+## 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-poll@1`: the poll an agent asks a Co-pilot room to run, and the result it gets back — the question and the two to four options the agent wrote, the window it is open for, the state (`open`, `closed` or `vetoed`) and the counts. An open poll carries no result, a closed one carries its counts and its winner, a vetoed one names who refused it.
+- Add `live.agent-stream-control@1`: one of the four controls the owner and the channel's moderators have over a live agent stream — `pause`, `curtain`, `mute` or `end` — with who pressed it (the handle and the role: owner or moderator) and when, and whose pause is in force.
+- Add the capabilities `chat.agent_digest.read` and `chat.agent_poll.write` (first-party), and name both in Chat's service manifest. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token `on_behalf_of`), so a digest is the owner's room and nobody else's.
+- `chat.preferences` is v2: it gains `agents_read_messages` ('Agents don't read my messages'). A v1 record upgrades with it true — joining a Co-pilot room and writing in it is the choice, and the person can take it back.
+- `live.agent_stream.publish` now names the controls (`POST /api/streams/agent/:id/control`, `GET /api/streams/agent/:id/controls`) and the step credit: a step may name the suggestion it took.
+- Additive: nothing that exists changes. Fixtures cover a digest over the ten-item cap, an unknown kind, a room that is not an agent room, a poll with one option and with five, an open poll carrying a result, an unknown control, a control with nobody behind it and a role that is neither owner nor moderator.
+
## 0.302.0 — 2026-11-06
## 0.302.0 — 2026-11-06
- Add the capabilities `media.avatar.adopt` and `media.avatar.release` (internal), and name both in Media's service manifest. After the 2026-11-06 incident (eleven avatars were soft-deleted with the public screenshot copies), Media records which avatar object each profile slot points at, and its delete refuses an object a working profile still shows. A product (Network for `users.avatar_url`, Live for its own copy and the channel banner) records a slot with `POST /internal/avatar-adopt` and drops it with `POST /internal/avatar-release`.
- Add the capabilities `media.avatar.adopt` and `media.avatar.release` (internal), and name both in Media's service manifest. After the 2026-11-06 incident (eleven avatars were soft-deleted with the public screenshot copies), Media records which avatar object each profile slot points at, and its delete refuses an object a working profile still shows. A product (Network for `users.avatar_url`, Live for its own copy and the channel banner) records a slot with `POST /internal/avatar-adopt` and drops it with `POST /internal/avatar-release`.
@@ -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.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)",
"798 JSON Schemas with valid and invalid fixtures (at v0.210.0)",
"45 service manifests with lifecycle declarations (39 alpha, 1 beta, 4 stable, 1 retired)",
"45 service manifests with lifecycle declarations (39 alpha, 1 beta, 4 stable, 1 retired)",
"348 capability manifests (306 active, 27 planned, 15 retired) and the staff capability map",
"348 capability manifests (306 active, 27 planned, 15 retired) and the staff capability map",
@@ -36,11 +38,11 @@
@@ -36,11 +38,11 @@
"OpenVibe.Food, OpenVibe.Help and OpenVibe.Work become services (plan T19); OpenVibe.Quest and OpenVibe.Rent become services",
"OpenVibe.Food, OpenVibe.Help and OpenVibe.Work become services (plan T19); OpenVibe.Quest and OpenVibe.Rent become services",
"the forum returns to Community; Deals goes live, with product copy for the new sites",
"the forum returns to Community; Deals goes live, with product copy for the new sites",
"OpenVibe.MediaHub goes live (openvibe.download as a private drive); services declare the account events they consume (ADR-033, SDK 0.37.0)",
"OpenVibe.MediaHub goes live (openvibe.download as a private drive); services declare the account events they consume (ADR-033, SDK 0.37.0)",
- "ADR-054 — the OpenVibe inventory authority (kinds, definitions, instances, equipped and the ledger), its planned service, capabilities, schemas and events (plan T21 step 1)",
+ "ADR-054 \u2014 the OpenVibe inventory authority (kinds, definitions, instances, equipped and the ledger), its planned service, capabilities, schemas and events (plan T21 step 1)",
"OpenVibe.Inventory goes live (inventory.openvibe.network, site position 30) with six capabilities active (ADR-054, plan T21 step 2); a definition may name the services or apps that may grant it",
"OpenVibe.Inventory goes live (inventory.openvibe.network, site position 30) with six capabilities active (ADR-054, plan T21 step 2); a definition may name the services or apps that may grant it",
"the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots",
"the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots",
"News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)",
"News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)",
- "ADR-055 (proposed): money and the inventory — primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",
+ "ADR-055 (proposed): money and the inventory \u2014 primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",
"bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)"
"bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)"
],
],
"updated": "2026-10-30"
"updated": "2026-10-30"
@@ -9511,6 +9511,33 @@
@@ -9511,6 +9511,33 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "chat.agent-digest",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/agent-digest.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "chat.agent-poll",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/agent-poll.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent-stream-control",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream-control.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
{
{
"id": "live.agent_stream.changed",
"id": "live.agent_stream.changed",
"version": "1.0.0",
"version": "1.0.0",
new file mode 100644
new file mode 100644
@@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/agent-digest.v1.json",
+ "title": "ChatAgentDigest",
+ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "room",
+ "since",
+ "until",
+ "items"
+ ],
+ "properties": {
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "The start of the window: the moment the agent last read, or null for the first read."
+ },
+ "until": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The end of the window: the moment this digest was made."
+ },
+ "items": {
+ "type": "array",
+ "maxItems": 10,
+ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "who",
+ "what",
+ "kind",
+ "upvotes"
+ ],
+ "properties": {
+ "who": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "display_name",
+ "handle"
+ ],
+ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",
+ "properties": {
+ "display_name": {
+ "type": "string",
+ "maxLength": 80,
+ "description": "The name the room shows."
+ },
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle, so the agent can answer this person by name."
+ }
+ }
+ },
+ "what": {
+ "type": "string",
+ "maxLength": 200,
+ "description": "What they said, cut to 200 characters. A link is kept as its domain only."
+ },
+ "kind": {
+ "enum": [
+ "question",
+ "suggestion",
+ "reaction"
+ ],
+ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."
+ },
+ "upvotes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many thumbs up the message carries. The most-upvoted items come first."
+ },
+ "repeated": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."
+ }
+ }
+ }
+ },
+ "chars": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1500,
+ "description": "How many characters the items use together, at most 1,500."
+ },
+ "truncated": {
+ "type": "boolean",
+ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,221 @@
@@ -0,0 +1,221 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/agent-poll.v1.json",
+ "title": "ChatAgentPoll",
+ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "poll_id",
+ "room",
+ "question",
+ "options",
+ "opened_at",
+ "closes_at",
+ "state"
+ ],
+ "properties": {
+ "poll_id": {
+ "type": "string",
+ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The poll's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "question": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The question the agent wrote."
+ },
+ "options": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^[1-4]$",
+ "description": "The option's number: `!1` to `!4` vote for it."
+ },
+ "label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80,
+ "description": "The option's text, as the agent wrote it."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people chose it. The count is in the result; it says nothing about who."
+ }
+ }
+ }
+ },
+ "opened_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll opened."
+ },
+ "closes_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."
+ },
+ "closed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."
+ },
+ "state": {
+ "enum": [
+ "open",
+ "closed",
+ "vetoed"
+ ],
+ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",
+ "required": [
+ "counts",
+ "total"
+ ],
+ "properties": {
+ "counts": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "How many votes each option got, in the order the options were written.",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ }
+ },
+ "total": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted."
+ },
+ "winner": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^[1-4]$",
+ "description": "The option that won, or null when there was no vote or no winner."
+ }
+ }
+ },
+ "vetoed_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "open"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "result": {
+ "type": "null"
+ },
+ "closed_at": {
+ "type": "null"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "closed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "result"
+ ],
+ "properties": {
+ "result": {
+ "type": "object"
+ },
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "vetoed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "vetoed_by"
+ ],
+ "properties": {
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
+{
+ "$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.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "control",
+ "by",
+ "at"
+ ],
+ "properties": {
+ "control": {
+ "enum": [
+ "pause",
+ "curtain",
+ "mute",
+ "end"
+ ],
+ "description": "Which control was pressed."
+ },
+ "by": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle",
+ "role"
+ ],
+ "description": "Who pressed it: the handle and the role they hold. Never an id, never anything else about them.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who pressed the control."
+ },
+ "role": {
+ "enum": [
+ "owner",
+ "moderator"
+ ],
+ "description": "What they are on this stream: the owner, or one of the channel's moderators."
+ }
+ }
+ },
+ "at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the control was pressed."
+ },
+ "stream": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent stream the control was pressed on."
+ },
+ "paused_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
+{
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "since": null,
+ "until": "2026-11-06T10:05:00.000Z",
+ "items": [
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ },
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "reaction",
+ "upvotes": 0
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "room": "chat:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "since": null,
+ "until": "2026-11-06T10:05:00.000Z",
+ "items": []
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
+{
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "since": null,
+ "until": "2026-11-06T10:05:00.000Z",
+ "items": [
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "hi",
+ "kind": "greeting",
+ "upvotes": 0
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "since": null,
+ "until": "2026-11-06T10:05:00.000Z",
+ "chars": 0,
+ "truncated": false,
+ "items": []
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
+{
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "since": "2026-11-06T10:00:00.000Z",
+ "until": "2026-11-06T10:05:00.000Z",
+ "chars": 120,
+ "truncated": false,
+ "items": [
+ {
+ "who": {
+ "display_name": "Mira",
+ "handle": "mira"
+ },
+ "what": "why is the test flaky?",
+ "kind": "question",
+ "upvotes": 3
+ },
+ {
+ "who": {
+ "display_name": "Sam",
+ "handle": "sam"
+ },
+ "what": "a link to github.com",
+ "kind": "suggestion",
+ "upvotes": 2,
+ "repeated": 2
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
+{
+ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "question": "Which name?",
+ "options": [
+ {
+ "id": "1",
+ "label": "a",
+ "votes": 0
+ },
+ {
+ "id": "2",
+ "label": "b",
+ "votes": 0
+ },
+ {
+ "id": "3",
+ "label": "c",
+ "votes": 0
+ },
+ {
+ "id": "4",
+ "label": "d",
+ "votes": 0
+ },
+ {
+ "id": "5",
+ "label": "e",
+ "votes": 0
+ }
+ ],
+ "opened_at": "2026-11-06T10:00:00.000Z",
+ "closes_at": "2026-11-06T10:01:00.000Z",
+ "state": "open"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
+{
+ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "question": "Which name?",
+ "options": [
+ {
+ "id": "1",
+ "label": "parseRows",
+ "votes": 0
+ }
+ ],
+ "opened_at": "2026-11-06T10:00:00.000Z",
+ "closes_at": "2026-11-06T10:01:00.000Z",
+ "state": "open"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
+{
+ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "question": "Which name?",
+ "options": [
+ {
+ "id": "1",
+ "label": "a",
+ "votes": 0
+ },
+ {
+ "id": "2",
+ "label": "b",
+ "votes": 0
+ }
+ ],
+ "opened_at": "2026-11-06T10:00:00.000Z",
+ "closes_at": "2026-11-06T10:01:00.000Z",
+ "state": "open",
+ "result": {
+ "counts": [
+ 1,
+ 0
+ ],
+ "total": 1,
+ "winner": "1"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "question": "Which name: parseRows or readTable?",
+ "options": [
+ {
+ "id": "1",
+ "label": "parseRows",
+ "votes": 4
+ },
+ {
+ "id": "2",
+ "label": "readTable",
+ "votes": 1
+ }
+ ],
+ "opened_at": "2026-11-06T10:00:00.000Z",
+ "closes_at": "2026-11-06T10:01:00.000Z",
+ "closed_at": "2026-11-06T10:01:00.000Z",
+ "state": "closed",
+ "result": {
+ "counts": [
+ 4,
+ 1
+ ],
+ "total": 5,
+ "winner": "1"
+ },
+ "vetoed_by": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "poll_id": "pol_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "room": "agent:ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "question": "Which name: parseRows or readTable?",
+ "options": [
+ {
+ "id": "1",
+ "label": "parseRows",
+ "votes": 0
+ },
+ {
+ "id": "2",
+ "label": "readTable",
+ "votes": 0
+ }
+ ],
+ "opened_at": "2026-11-06T10:00:00.000Z",
+ "closes_at": "2026-11-06T10:01:00.000Z",
+ "closed_at": null,
+ "state": "open",
+ "result": null,
+ "vetoed_by": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "control": "pause",
+ "at": "2026-11-06T10:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "control": "pause",
+ "by": {
+ "handle": "mod",
+ "role": "viewer"
+ },
+ "at": "2026-11-06T10:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "control": "nuke",
+ "by": {
+ "handle": "mod",
+ "role": "moderator"
+ },
+ "at": "2026-11-06T10:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "control": "end",
+ "by": {
+ "handle": "owner",
+ "role": "owner"
+ },
+ "at": "2026-11-06T10:00:00.000Z",
+ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "paused_by": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "control": "pause",
+ "by": {
+ "handle": "mod",
+ "role": "moderator"
+ },
+ "at": "2026-11-06T10:00:00.000Z",
+ "stream": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "paused_by": "mod"
+}
@@ -104271,6 +104271,411 @@
@@ -104271,6 +104271,411 @@
}
}
}
}
},
},
+ "chat.agent-digest": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/agent-digest.v1.json",
+ "title": "ChatAgentDigest",
+ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "room",
+ "since",
+ "until",
+ "items"
+ ],
+ "properties": {
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "The start of the window: the moment the agent last read, or null for the first read."
+ },
+ "until": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The end of the window: the moment this digest was made."
+ },
+ "items": {
+ "type": "array",
+ "maxItems": 10,
+ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "who",
+ "what",
+ "kind",
+ "upvotes"
+ ],
+ "properties": {
+ "who": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "display_name",
+ "handle"
+ ],
+ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",
+ "properties": {
+ "display_name": {
+ "type": "string",
+ "maxLength": 80,
+ "description": "The name the room shows."
+ },
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle, so the agent can answer this person by name."
+ }
+ }
+ },
+ "what": {
+ "type": "string",
+ "maxLength": 200,
+ "description": "What they said, cut to 200 characters. A link is kept as its domain only."
+ },
+ "kind": {
+ "enum": [
+ "question",
+ "suggestion",
+ "reaction"
+ ],
+ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."
+ },
+ "upvotes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many thumbs up the message carries. The most-upvoted items come first."
+ },
+ "repeated": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."
+ }
+ }
+ }
+ },
+ "chars": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1500,
+ "description": "How many characters the items use together, at most 1,500."
+ },
+ "truncated": {
+ "type": "boolean",
+ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."
+ }
+ }
+ }
+ },
+ "chat.agent-poll": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/agent-poll.v1.json",
+ "title": "ChatAgentPoll",
+ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "poll_id",
+ "room",
+ "question",
+ "options",
+ "opened_at",
+ "closes_at",
+ "state"
+ ],
+ "properties": {
+ "poll_id": {
+ "type": "string",
+ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The poll's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "question": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The question the agent wrote."
+ },
+ "options": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^[1-4]$",
+ "description": "The option's number: `!1` to `!4` vote for it."
+ },
+ "label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80,
+ "description": "The option's text, as the agent wrote it."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people chose it. The count is in the result; it says nothing about who."
+ }
+ }
+ }
+ },
+ "opened_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll opened."
+ },
+ "closes_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."
+ },
+ "closed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."
+ },
+ "state": {
+ "enum": [
+ "open",
+ "closed",
+ "vetoed"
+ ],
+ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",
+ "required": [
+ "counts",
+ "total"
+ ],
+ "properties": {
+ "counts": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "How many votes each option got, in the order the options were written.",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ }
+ },
+ "total": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted."
+ },
+ "winner": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^[1-4]$",
+ "description": "The option that won, or null when there was no vote or no winner."
+ }
+ }
+ },
+ "vetoed_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "open"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "result": {
+ "type": "null"
+ },
+ "closed_at": {
+ "type": "null"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "closed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "result"
+ ],
+ "properties": {
+ "result": {
+ "type": "object"
+ },
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "vetoed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "vetoed_by"
+ ],
+ "properties": {
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "live.agent-stream-control": {
+ "version": "1.0.0",
+ "owner": "live",
+ "status": "active",
+ "schema": {
+ "$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.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "control",
+ "by",
+ "at"
+ ],
+ "properties": {
+ "control": {
+ "enum": [
+ "pause",
+ "curtain",
+ "mute",
+ "end"
+ ],
+ "description": "Which control was pressed."
+ },
+ "by": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "handle",
+ "role"
+ ],
+ "description": "Who pressed it: the handle and the role they hold. Never an id, never anything else about them.",
+ "properties": {
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle of the person who pressed the control."
+ },
+ "role": {
+ "enum": [
+ "owner",
+ "moderator"
+ ],
+ "description": "What they are on this stream: the owner, or one of the channel's moderators."
+ }
+ }
+ },
+ "at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the control was pressed."
+ },
+ "stream": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent stream the control was pressed on."
+ },
+ "paused_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is."
+ }
+ }
+ }
+ },
"live.agent_stream.changed": {
"live.agent_stream.changed": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "live",
"owner": "live",
@@ -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.302.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3709,6 +3709,491 @@
@@ -3709,6 +3709,491 @@
}
}
}
}
},
},
+ "/internal/chat/rooms/agent{digest}": {
+ "get": {
+ "operationId": "get_internal_chat_rooms_agentdigest",
+ "summary": "Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5).",
+ "description": "**chat.agent_digest.read** (first-party): Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5). GET /internal/chat/rooms/agent:digest?since= answers chat.agent-digest@1: at most ten items and 1,500 characters, each with who (the display name and the handle), what (cut to 200 characters), its kind (a question, a suggestion or a reaction) and its upvotes. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of), so the digest is the owner's room and nobody else's. Chat chooses what goes in 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' is never in the digest, and a link is kept as its domain only. The agent never reads the raw room, and one read per step at most, twenty seconds apart.",
+ "tags": [
+ "chat.agent_digest"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.agent_digest.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.agent_digest.read"
+ ]
+ }
+ ],
+ "x-openvibe-input": {
+ "$ref": "#/components/schemas/chat.agent-digest.v1"
+ },
+ "parameters": [
+ {
+ "name": "digest",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "room",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."
+ },
+ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."
+ },
+ {
+ "name": "since",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "The start of the window: the moment the agent last read, or null for the first read."
+ },
+ "description": "The start of the window: the moment the agent last read, or null for the first read."
+ },
+ {
+ "name": "until",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The end of the window: the moment this digest was made."
+ },
+ "description": "The end of the window: the moment this digest was made."
+ },
+ {
+ "name": "items",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "maxItems": 10,
+ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "who",
+ "what",
+ "kind",
+ "upvotes"
+ ],
+ "properties": {
+ "who": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "display_name",
+ "handle"
+ ],
+ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",
+ "properties": {
+ "display_name": {
+ "type": "string",
+ "maxLength": 80,
+ "description": "The name the room shows."
+ },
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle, so the agent can answer this person by name."
+ }
+ }
+ },
+ "what": {
+ "type": "string",
+ "maxLength": 200,
+ "description": "What they said, cut to 200 characters. A link is kept as its domain only."
+ },
+ "kind": {
+ "enum": [
+ "question",
+ "suggestion",
+ "reaction"
+ ],
+ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."
+ },
+ "upvotes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many thumbs up the message carries. The most-upvoted items come first."
+ },
+ "repeated": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."
+ }
+ }
+ }
+ },
+ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last."
+ },
+ {
+ "name": "chars",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1500,
+ "description": "How many characters the items use together, at most 1,500."
+ },
+ "description": "How many characters the items use together, at most 1,500."
+ },
+ {
+ "name": "truncated",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."
+ },
+ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.agent-digest.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",
+ "summary": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5).",
+ "description": "**chat.agent_poll.write** (first-party): Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",
+ "tags": [
+ "chat.agent_poll"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.agent_poll.write"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.agent_poll.write"
+ ]
+ }
+ ],
+ "x-openvibe-input": {
+ "$ref": "#/components/schemas/chat.agent-poll.v1"
+ },
+ "parameters": [
+ {
+ "name": "poll",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "poll_id",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The poll's id (ULID, Crockford base32)."
+ },
+ "description": "The poll'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 poll is in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."
+ },
+ {
+ "name": "question",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The question the agent wrote."
+ },
+ "description": "The question the agent wrote."
+ },
+ {
+ "name": "options",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^[1-4]$",
+ "description": "The option's number: `!1` to `!4` vote for it."
+ },
+ "label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80,
+ "description": "The option's text, as the agent wrote it."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people chose it. The count is in the result; it says nothing about who."
+ }
+ }
+ }
+ },
+ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own."
+ },
+ {
+ "name": "opened_at",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll opened."
+ },
+ "description": "When the poll opened."
+ },
+ {
+ "name": "closes_at",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."
+ },
+ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."
+ },
+ {
+ "name": "closed_at",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."
+ },
+ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "enum": [
+ "open",
+ "closed",
+ "vetoed"
+ ],
+ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."
+ },
+ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."
+ },
+ {
+ "name": "result",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",
+ "required": [
+ "counts",
+ "total"
+ ],
+ "properties": {
+ "counts": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "How many votes each option got, in the order the options were written.",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ }
+ },
+ "total": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted."
+ },
+ "winner": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^[1-4]$",
+ "description": "The option that won, or null when there was no vote or no winner."
+ }
+ }
+ },
+ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open."
+ },
+ {
+ "name": "vetoed_by",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."
+ },
+ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.agent-poll.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "post_internal_chat_rooms_agentpoll",
+ "summary": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5).",
+ "description": "**chat.agent_poll.write** (first-party): Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",
+ "tags": [
+ "chat.agent_poll"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.agent_poll.write"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.agent_poll.write"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.agent-poll.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "poll",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.agent-poll.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/internal/chat/sounds": {
"/internal/chat/sounds": {
"get": {
"get": {
"operationId": "get_internal_chat_sounds",
"operationId": "get_internal_chat_sounds",
@@ -4478,6 +4963,328 @@
@@ -4478,6 +4963,328 @@
},
},
"components": {
"components": {
"schemas": {
"schemas": {
+ "chat.agent-digest.v1": {
+ "title": "ChatAgentDigest",
+ "description": "chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "room",
+ "since",
+ "until",
+ "items"
+ ],
+ "properties": {
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the digest came from: an agent stream's room, `agent:<ags_id>`."
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "The start of the window: the moment the agent last read, or null for the first read."
+ },
+ "until": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The end of the window: the moment this digest was made."
+ },
+ "items": {
+ "type": "array",
+ "maxItems": 10,
+ "description": "What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "who",
+ "what",
+ "kind",
+ "upvotes"
+ ],
+ "properties": {
+ "who": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "display_name",
+ "handle"
+ ],
+ "description": "Who said it: the display name and the handle. Never an id, never an email, never anything else about them.",
+ "properties": {
+ "display_name": {
+ "type": "string",
+ "maxLength": 80,
+ "description": "The name the room shows."
+ },
+ "handle": {
+ "type": "string",
+ "pattern": "^[a-z0-9_]{2,32}$",
+ "description": "The handle, so the agent can answer this person by name."
+ }
+ }
+ },
+ "what": {
+ "type": "string",
+ "maxLength": 200,
+ "description": "What they said, cut to 200 characters. A link is kept as its domain only."
+ },
+ "kind": {
+ "enum": [
+ "question",
+ "suggestion",
+ "reaction"
+ ],
+ "description": "What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do."
+ },
+ "upvotes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many thumbs up the message carries. The most-upvoted items come first."
+ },
+ "repeated": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "How many people said this same thing. Chat groups repeats into one item; this is the number behind it."
+ }
+ }
+ }
+ },
+ "chars": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1500,
+ "description": "How many characters the items use together, at most 1,500."
+ },
+ "truncated": {
+ "type": "boolean",
+ "description": "True when Chat left something out because of the ten-item or 1,500-character cap."
+ }
+ }
+ },
+ "chat.agent-poll.v1": {
+ "title": "ChatAgentPoll",
+ "description": "chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "poll_id",
+ "room",
+ "question",
+ "options",
+ "opened_at",
+ "closes_at",
+ "state"
+ ],
+ "properties": {
+ "poll_id": {
+ "type": "string",
+ "pattern": "^pol_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The poll's id (ULID, Crockford base32)."
+ },
+ "room": {
+ "type": "string",
+ "pattern": "^agent:ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The room the poll is in: an agent stream's room, `agent:<ags_id>`."
+ },
+ "question": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The question the agent wrote."
+ },
+ "options": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "The options the agent wrote, two to four of them. Chat never adds an option of its own.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^[1-4]$",
+ "description": "The option's number: `!1` to `!4` vote for it."
+ },
+ "label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80,
+ "description": "The option's text, as the agent wrote it."
+ },
+ "votes": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people chose it. The count is in the result; it says nothing about who."
+ }
+ }
+ }
+ },
+ "opened_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll opened."
+ },
+ "closes_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "When the poll closes on its own: 30 to 120 seconds after it opened."
+ },
+ "closed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the poll was closed early by the owner or a moderator, or null when it ran its time."
+ },
+ "state": {
+ "enum": [
+ "open",
+ "closed",
+ "vetoed"
+ ],
+ "description": "Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result)."
+ },
+ "result": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "description": "The result, once the poll is closed: the counts and the winning option. Null while the poll is open.",
+ "required": [
+ "counts",
+ "total"
+ ],
+ "properties": {
+ "counts": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 4,
+ "description": "How many votes each option got, in the order the options were written.",
+ "items": {
+ "type": "integer",
+ "minimum": 0
+ }
+ },
+ "total": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How many people voted."
+ },
+ "winner": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^[1-4]$",
+ "description": "The option that won, or null when there was no vote or no winner."
+ }
+ }
+ },
+ "vetoed_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only."
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "open"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "properties": {
+ "result": {
+ "type": "null"
+ },
+ "closed_at": {
+ "type": "null"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "closed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "result"
+ ],
+ "properties": {
+ "result": {
+ "type": "object"
+ },
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "null"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "vetoed"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "then": {
+ "required": [
+ "closed_at",
+ "vetoed_by"
+ ],
+ "properties": {
+ "closed_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "vetoed_by": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ },
"chat.channel-moderation-result.v1": {
"chat.channel-moderation-result.v1": {
"title": "ChatChannelModerationResult",
"title": "ChatChannelModerationResult",
"description": "chat.channel-moderation-result@1: the answer of GET /internal/moderation/channels/:channelId on OpenVibe.Chat (capability chat.moderation.read): { ok: true, settings, moderator_ids } — one channel's moderation settings and the ids of the people who moderate it, for OpenVibe.Live's stream chat. settings carries every channel_moderation_settings column (Live's own defaults when the channel has no row yet, database.js getChannelModerationSettings); the switches are 0/1 as the table stores them. moderator_ids are Live user ids (channel_moderators.user_id), never names. A failure is { ok: false, error }; a caller without the grant gets 401 { ok: false }.",
"description": "chat.channel-moderation-result@1: the answer of GET /internal/moderation/channels/:channelId on OpenVibe.Chat (capability chat.moderation.read): { ok: true, settings, moderator_ids } — one channel's moderation settings and the ids of the people who moderate it, for OpenVibe.Live's stream chat. settings carries every channel_moderation_settings column (Live's own defaults when the channel has no row yet, database.js getChannelModerationSettings); the switches are 0/1 as the table stores them. moderator_ids are Live user ids (channel_moderators.user_id), never names. A failure is { ok: false, error }; a caller without the grant gets 401 { ok: false }.",
@@ -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.302.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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": 55,
- "capabilities": 20
+ "operations": 58,
+ "capabilities": 22
},
},
{
{
"service": "codes",
"service": "codes",
@@ -124,7 +124,7 @@
@@ -124,7 +124,7 @@
"service": "live",
"service": "live",
"name": "OpenVibe.Live",
"name": "OpenVibe.Live",
"origin": "https://openvibe.live",
"origin": "https://openvibe.live",
- "operations": 38,
+ "operations": 40,
"capabilities": 11
"capabilities": 11
},
},
{
{
@@ -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.302.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -694,7 +694,7 @@
@@ -694,7 +694,7 @@
"post": {
"post": {
"operationId": "post_api_streams_agent",
"operationId": "post_api_streams_agent",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -746,11 +746,181 @@
@@ -746,11 +746,181 @@
}
}
}
}
},
},
+ "/api/streams/agent/{id}/control": {
+ "post": {
+ "operationId": "post_api_streams_agent_id_control",
+ "summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "tags": [
+ "live.agent_stream"
+ ],
+ "x-openvibe-capabilities": [
+ "live.agent_stream.publish"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "standard",
+ "security": [
+ {
+ "openvibeToken": [
+ "live.agent_stream.publish"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/live.agent-stream-create-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/live.agent-stream-publish.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/streams/agent/{id}/controls": {
+ "get": {
+ "operationId": "get_api_streams_agent_id_controls",
+ "summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "tags": [
+ "live.agent_stream"
+ ],
+ "x-openvibe-capabilities": [
+ "live.agent_stream.publish"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "standard",
+ "security": [
+ {
+ "openvibeToken": [
+ "live.agent_stream.publish"
+ ]
+ }
+ ],
+ "x-openvibe-input": {
+ "$ref": "#/components/schemas/live.agent-stream-create-request.v1"
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "title",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ }
+ },
+ {
+ "name": "task",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"
+ }
+ },
+ {
+ "name": "visibility",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ }
+ },
+ {
+ "name": "allow_sites",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "array",
+ "maxItems": 50,
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "description": "The hosts the browser desk may visit. Absent means no limit."
+ },
+ "description": "The hosts the browser desk may visit. Absent means no limit."
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/live.agent-stream-publish.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/streams/agent/{id}/curtain": {
"/api/streams/agent/{id}/curtain": {
"post": {
"post": {
"operationId": "post_api_streams_agent_id_curtain",
"operationId": "post_api_streams_agent_id_curtain",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -816,7 +986,7 @@
@@ -816,7 +986,7 @@
"post": {
"post": {
"operationId": "post_api_streams_agent_id_end",
"operationId": "post_api_streams_agent_id_end",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -882,7 +1052,7 @@
@@ -882,7 +1052,7 @@
"put": {
"put": {
"operationId": "put_api_streams_agent_id_frame",
"operationId": "put_api_streams_agent_id_frame",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -948,7 +1118,7 @@
@@ -948,7 +1118,7 @@
"get": {
"get": {
"operationId": "get_api_streams_agent_id_state",
"operationId": "get_api_streams_agent_id_state",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -1052,7 +1222,7 @@
@@ -1052,7 +1222,7 @@
"delete": {
"delete": {
"operationId": "delete_api_streams_agent_id_ticket",
"operationId": "delete_api_streams_agent_id_ticket",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -1154,7 +1324,7 @@
@@ -1154,7 +1324,7 @@
"post": {
"post": {
"operationId": "post_api_streams_agent_id_ticket",
"operationId": "post_api_streams_agent_id_ticket",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
"summary": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1).",
- "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "**live.agent_stream.publish** (public): Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"tags": [
"tags": [
"live.agent_stream"
"live.agent_stream"
],
],
@@ -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.302.0",
- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"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.302.0",
- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.302.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.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.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -292529,6 +292529,2001 @@ export interface LiveAgentStreamStepRequest {
@@ -292529,6 +292529,2001 @@ export interface LiveAgentStreamStepRequest {
cost_usd?: number;
cost_usd?: number;
}
}
+/** [email protected] (owner: chat) */
+/**
+ * chat.agent-digest@1 (the Agent Streams plan, S5): what a chat room said to an agent between two of its steps, GET /api/v1/rooms/agent:<id>/digest?since= on OpenVibe.Chat. The agent never reads the raw room: it asks 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 (a question, a suggestion or a reaction) and its upvotes (a thumbs up on the message counts). Chat chooses what goes in: repeats are grouped, greetings and spam are dropped, and the most-upvoted questions and suggestions come first. Nobody is left out by accident: a person who is timed out or banned, whose account is younger than a day, or who set 'Agents don't read my messages' is never in the digest. A link is kept as its domain only ('a link to github.com'), because the agent never follows a link from chat. The code and the commands stay as text: the agent's own tools and approvals decide what may run, never chat.
+ */
+export interface ChatAgentDigest {
+ /**
+ * The room the digest came from: an agent stream's room, `agent:<ags_id>`.
+ */
+ room: string;
+ /**
+ * The start of the window: the moment the agent last read, or null for the first read.
+ */
+ since: string | null;
+ /**
+ * The end of the window: the moment this digest was made.
+ */
+ until: string;
+ /**
+ * What chat said, at most ten items. The order is the one Chat chose: the most-upvoted questions and suggestions first, the reactions last.
+ *
+ * @maxItems 10
+ */
+ items:
+ | []
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ },
+ {
+ /**
+ * Who said it: the display name and the handle. Never an id, never an email, never anything else about them.
+ */
+ who: {
+ /**
+ * The name the room shows.
+ */
+ display_name: string;
+ /**
+ * The handle, so the agent can answer this person by name.
+ */
+ handle: string;
+ };
+ /**
+ * What they said, cut to 200 characters. A link is kept as its domain only.
+ */
+ what: string;
+ /**
+ * What the line is: a question the agent may answer, a suggestion it may take or leave, or a reaction (a thumbs up, a cheer) that says nothing to do.
+ */
+ kind: "question" | "suggestion" | "reaction";
+ /**
+ * How many thumbs up the message carries. The most-upvoted items come first.
+ */
+ upvotes: number;
+ /**
+ * How many people said this same thing. Chat groups repeats into one item; this is the number behind it.
+ */
+ repeated?: number;
+ }
+ ];
+ /**
+ * How many characters the items use together, at most 1,500.
+ */
+ chars?: number;
+ /**
+ * True when Chat left something out because of the ten-item or 1,500-character cap.
+ */
+ truncated?: boolean;
+}
+
+/** [email protected] (owner: chat) */
+/**
+ * chat.agent-poll@1 (the Agent Streams plan, S5): a poll the agent asks a Co-pilot room to run, and the result it gets back. The agent writes the question and two to four options ('Which name: parseRows or readTable?') and the poll is open for 30 to 120 seconds. Chat draws it as a poll card with buttons; `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner (or a moderator) can close a poll early or veto its result. A poll can only choose between the options the agent wrote: Chat never adds one. The result carries the counts, nothing else about who voted.
+ */
+export type ChatAgentPoll = {
+ [k: string]: unknown | undefined;
+} & {
+ /**
+ * The poll's id (ULID, Crockford base32).
+ */
+ poll_id: string;
+ /**
+ * The room the poll is in: an agent stream's room, `agent:<ags_id>`.
+ */
+ room: string;
+ /**
+ * The question the agent wrote.
+ */
+ question: string;
+ /**
+ * The options the agent wrote, two to four of them. Chat never adds an option of its own.
+ *
+ * @minItems 2
+ * @maxItems 4
+ */
+ options:
+ | [
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ }
+ ]
+ | [
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ },
+ {
+ /**
+ * The option's number: `!1` to `!4` vote for it.
+ */
+ id: string;
+ /**
+ * The option's text, as the agent wrote it.
+ */
+ label: string;
+ /**
+ * How many people chose it. The count is in the result; it says nothing about who.
+ */
+ votes?: number;
+ }
+ ];
+ /**
+ * When the poll opened.
+ */
+ opened_at: string;
+ /**
+ * When the poll closes on its own: 30 to 120 seconds after it opened.
+ */
+ closes_at: string;
+ /**
+ * When the poll was closed early by the owner or a moderator, or null when it ran its time.
+ */
+ closed_at?: string | null;
+ /**
+ * Where the poll stands: open, closed (the counts are final), or vetoed (the owner or a moderator refused the result).
+ */
+ state: "open" | "closed" | "vetoed";
+ /**
+ * The result, once the poll is closed: the counts and the winning option. Null while the poll is open.
+ */
+ result?: {
+ /**
+ * How many votes each option got, in the order the options were written.
+ *
+ * @minItems 2
+ * @maxItems 4
+ */
+ counts: [number, number] | [number, number, number] | [number, number, number, number];
+ /**
+ * How many people voted.
+ */
+ total: number;
+ /**
+ * The option that won, or null when there was no vote or no winner.
+ */
+ winner?: string | null;
+ } | null;
+ /**
+ * Who vetoed the result (the owner or a moderator), or null. Never a person's id: the handle only.
+ */
+ vetoed_by?: string | null;
+};
+
+/** [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.
+ */
+export interface LiveAgentStreamControl {
+ /**
+ * Which control was pressed.
+ */
+ control: "pause" | "curtain" | "mute" | "end";
+ /**
+ * Who pressed it: the handle and the role they hold. Never an id, never anything else about them.
+ */
+ by: {
+ /**
+ * The handle of the person who pressed the control.
+ */
+ handle: string;
+ /**
+ * What they are on this stream: the owner, or one of the channel's moderators.
+ */
+ role: "owner" | "moderator";
+ };
+ /**
+ * When the control was pressed.
+ */
+ at: string;
+ /**
+ * The agent stream the control was pressed on.
+ */
+ stream?: string;
+ /**
+ * The handle of the person whose pause is in force, or null when the stream is not paused. A moderator cannot resume the owner's pause: this says whose it is.
+ */
+ paused_by?: string | null;
+}
+
/** [email protected] (owner: live) */
/** [email protected] (owner: live) */
/**
/**
* live.agent_stream.changed v1 (OpenVibe.Live, the Agent Streams plan, S1): an agent stream changed. KIND is what happened: started, ended, visibility (the owner switched it) or curtain (the desk's privacy screen went up or came down). It says what happened and never why: the curtain's reason stays with the owner, so a subscriber learns that a private screen is up, not that a password field was focused. VISIBILITY carries the new visibility when KIND is visibility, CURTAIN whether the screen is up when KIND is curtain. The publish ticket, the stream key and the task's contents never appear. Envelope: subject { type: agent_stream, id: ags_… }, actor the owner's subject when Live knows it, else service:live. The event type carries no hyphen (events.event-envelope@1's event_type pattern allows letters, digits and underscores only), so it is live.agent_stream.changed; the stream's contract ids keep live.agent-stream@1.
* live.agent_stream.changed v1 (OpenVibe.Live, the Agent Streams plan, S1): an agent stream changed. KIND is what happened: started, ended, visibility (the owner switched it) or curtain (the desk's privacy screen went up or came down). It says what happened and never why: the curtain's reason stays with the owner, so a subscriber learns that a private screen is up, not that a password field was focused. VISIBILITY carries the new visibility when KIND is visibility, CURTAIN whether the screen is up when KIND is curtain. The publish ticket, the stream key and the task's contents never appear. Envelope: subject { type: agent_stream, id: ags_… }, actor the owner's subject when Live knows it, else service:live. The event type carries no hyphen (events.event-envelope@1's event_type pattern allows letters, digits and underscores only), so it is live.agent_stream.changed; the stream's contract ids keep live.agent-stream@1.
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "chat.agent_digest.read",
+ "version": "1.0",
+ "owner": "chat",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Read what a Co-pilot room said, as a digest, on OpenVibe.Chat (the Agent Streams plan, S5). GET /internal/chat/rooms/agent:digest?since= answers chat.agent-digest@1: at most ten items and 1,500 characters, each with who (the display name and the handle), what (cut to 200 characters), its kind (a question, a suggestion or a reaction) and its upvotes. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of), so the digest is the owner's room and nobody else's. Chat chooses what goes in 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' is never in the digest, and a link is kept as its domain only. The agent never reads the raw room, and one read per step at most, twenty seconds apart.",
+ "permissions": [
+ "chat:read"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-read",
+ "events": [],
+ "implementedBy": [
+ "GET /internal/chat/rooms/agent:digest"
+ ],
+ "inputSchema": "chat.agent-digest@1",
+ "outputSchema": "chat.agent-digest@1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+{
+ "id": "chat.agent_poll.write",
+ "version": "1.0",
+ "owner": "chat",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Run a poll in a Co-pilot room on OpenVibe.Chat, and read its result (the Agent Streams plan, S5). POST /internal/chat/rooms/agent:poll takes chat.agent-poll@1: the question and two to four options the agent wrote, open for 30 to 120 seconds; Chat draws the poll card and `!1` to `!4` vote too. One vote per person, one poll at a time, and at most one poll every five minutes. The owner or a moderator can close a poll early or veto its result. The caller is Codes or Actor, the task's service, acting for the stream's owner (a node token on_behalf_of). Chat never adds an option of its own: a poll can only choose between the options the agent wrote.",
+ "permissions": [
+ "chat:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-write",
+ "events": [],
+ "implementedBy": [
+ "POST /internal/chat/rooms/agent:poll",
+ "GET /internal/chat/rooms/agent:poll"
+ ],
+ "inputSchema": "chat.agent-poll@1",
+ "outputSchema": "chat.agent-poll@1"
+}
@@ -4,7 +4,7 @@
@@ -4,7 +4,7 @@
"owner": "live",
"owner": "live",
"status": "active",
"status": "active",
"visibility": "public",
"visibility": "public",
- "description": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode. The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
+ "description": "Publish an agent's stream on OpenVibe.Live (the Agent Streams plan, S1). POST /api/streams/agent creates the agent stream and its publish ticket, POST /api/streams/agent/:id/ticket renews that ticket, DELETE /api/streams/agent/:id/ticket revokes it (the kill switch: Live ends the WHIP session at once), POST /api/streams/agent/:id/curtain raises the desk's privacy screen, PUT /api/streams/agent/:id/frame sends the last frame while Live wants no video, POST /api/streams/agent/:id/end ends the stream, and GET /api/streams/agent/:id/state tells the desk whether to encode, and POST /api/streams/agent/:id/control is one of the four controls (pause, curtain, mute, end) with the moderator rules of the Agent Streams plan, S5. The publish capability also covers the step credit: a step may name the suggestion it took (\"Suggested by @mira\"). The caller is the person's own session token, or a first-party service token acting for that person (a Node principal acting for its owner, Codes or Actor) that holds this capability for the audience openvibe.live: Network grants it to exactly those principals. Never a developer-app token, never another person's stream. The Agent Streams design calls it live.agent-stream.publish; a capability id in this system carries no hyphen (the capability pattern and the token claims' cap pattern both allow letters, digits and underscores only), so the id is live.agent_stream.publish.",
"inputSchema": "live.agent-stream-create-request@1",
"inputSchema": "live.agent-stream-create-request@1",
"outputSchema": "live.agent-stream-publish@1",
"outputSchema": "live.agent-stream-publish@1",
"permissions": [
"permissions": [
@@ -24,7 +24,9 @@
@@ -24,7 +24,9 @@
"POST /api/streams/agent/:id/curtain",
"POST /api/streams/agent/:id/curtain",
"PUT /api/streams/agent/:id/frame",
"PUT /api/streams/agent/:id/frame",
"POST /api/streams/agent/:id/end",
"POST /api/streams/agent/:id/end",
- "GET /api/streams/agent/:id/state"
+ "GET /api/streams/agent/:id/state",
+ "POST /api/streams/agent/:id/control",
+ "GET /api/streams/agent/:id/controls"
],
],
"sensitive": true
"sensitive": true
}
}
@@ -1,8 +1,9 @@
@@ -1,8 +1,9 @@
{
{
"namespace": "chat.preferences",
"namespace": "chat.preferences",
"owner": "chat",
"owner": "chat",
- "version": 1,
- "description": "How chat looks for this person on every site with OpenVibe chat: timestamps, compact messages, text size, badges and emotes.",
+ "version": 2,
+ "migration": "v2 adds agents_read_messages (the Agent Streams plan, S5: 'Agents don't read my messages'). A v1 record upgrades to a v2 record that reads true: joining a Co-pilot room and writing in it is the choice, and the person can take it back.",
+ "description": "How chat looks for this person on every site with OpenVibe chat: timestamps, compact messages, text size, badges and emotes, and whether an AI agent may read their messages (the Co-pilot rooms of the Agent Streams plan, S5).",
"writers": [
"writers": [
"owner",
"owner",
"user"
"user"
@@ -30,7 +31,20 @@
@@ -30,7 +31,20 @@
},
},
"hide_emotes": {
"hide_emotes": {
"type": "boolean"
"type": "boolean"
+ },
+ "agents_read_messages": {
+ "type": "boolean",
+ "description": "Whether an AI agent may read this person's chat messages. True by default: joining a Co-pilot room and writing in it is the choice, and it can be taken back. When false the digest leaves this person out entirely."
+ }
+ }
+ },
+ "migrations": [
+ {
+ "from": 1,
+ "to": 2,
+ "defaults": {
+ "agents_read_messages": true
}
}
}
}
- }
+ ]
}
}
@@ -12,6 +12,8 @@
@@ -12,6 +12,8 @@
],
],
"publicOrigin": "https://openvibe.chat",
"publicOrigin": "https://openvibe.chat",
"capabilities": [
"capabilities": [
+ "chat.agent_digest.read",
+ "chat.agent_poll.write",
"chat.analysis.read",
"chat.analysis.read",
"chat.cache.invalidate",
"chat.cache.invalidate",
"chat.event.publish",
"chat.event.publish",
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.301.0",
+ "version": "0.302.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.301.0",
+ "version": "0.302.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.302.0",
+ "version": "0.303.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",