openvibers/openvibe.contracts Commits
Agent Streams S1: live.agent-stream@1, its schemas, the event and the Live publish capability (0.298.0) (#307)
Changes
@@@ -1,8 +1,16 @@# Changelog++## 0.298.0 — 2026-11-06++++- Add `live.agent-stream@1`: an agent's own stream on OpenVibe.Live (the Agent Streams plan, S1). It is a `managed_streams` row of kind `agent` with an `ags_<ULID>` id, no stream key and no normal slot; it carries the owner, the channel, the task it is doing (`codes`, `actor`, `desk` or `node`), the visibility (`private`, `unlisted`, `public`), the mode (`watch` in S1), the state, the curtain, the viewers, the worked seconds, the last frame, the VOD and the page. The card stays after the stream ends.++- Add the four request/result schemas: `live.agent-stream-create-request@1` (title, task, visibility, the optional `allow_sites`), `live.agent-stream-publish@1` (`whip_url`, the one-time publish ticket `wpt_…`, `expires_at`), `live.agent-stream-state@1` (viewers, `encode`, the curtain and `ends_at`, what the desk polls) and `live.agent-stream-curtain-request@1` (`up` and the reason).++- Add the event `live.agent_stream.changed` (`started`, `ended`, `visibility`, `curtain`, never the reason) and the capability `live.agent_stream.publish`, and name both in Live's service manifest. The stream's contract ids keep the design's hyphen (`live.agent-stream@1`); the capability and the event type carry an underscore because `identity.service-token-claims@1`'s `cap` pattern and `events.event-envelope@1`'s `event_type` pattern allow letters, digits and underscores only. The capability's description records the design's `live.agent-stream.publish` name and why it is written `live.agent_stream.publish`. `identity.service-token-claims@1`'s `on_behalf_of` description now says a node token names its owner on the audience where the machine acts for them (Live's), so a receiver knows where to read the stream's owner.++- Valid and invalid fixtures cover the stream, the create request, the publish part, the state, the curtain request and the event payload, so a missing field, a bad id or a reason outside the list fails the run.++## 0.297.0 — 2026-11-06- Add `identity.subject-assertion-claims@1`: the claims of a short-lived ES256 assertion signed by OpenVibe.Network that says a person allowed one service to act for them on another service — `sub` (the person), `aud` (the service it is for), `act` (the service it was minted for), optionally `for` (the services that may carry it), `jti`, `iat`, `exp`. Network mints one only from the person's own access token (`POST /internal/subject-assertions`), so a service that merely knows a person's id cannot say the person allowed anything; the key is published in Network's JWKS (`kid ov-network-assertion-1`). The money routes of Billing and Tips check it against the person they act for, and refuse the old "the service vouches for its person" way once `BILLING_REQUIRE_SUBJECT_ASSERTION` / `TIPS_REQUIRE_SUBJECT_ASSERTION` is on. Only a service token Network issued for its own API (`openvibe.network`) mints one. See the ADR-003 amendment of 2026-11-06.++## 0.296.0 — 2026-11-06- Sharing learns locked items. `share.update-request@1` gains `envelope`: a `locker.envelope@1`, base64, the content re-sealed for the people who stay, sent with the members that remain when someone is removed from a people-locked item. The service stores it before it drops the member; it never opens it.@@@ -9402,6 +9402,60 @@"visibility": "public","compatibility": "backward","status": "active"++ },++ {++ "id": "live.agent-stream",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent-stream-create-request",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream-create-request.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent-stream-publish",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream-publish.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent-stream-state",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream-state.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent-stream-curtain-request",++ "version": "1.0.0",++ "owner": "live",++ "schema": "live/agent-stream-curtain-request.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "live.agent_stream.changed",++ "version": "1.0.0",++ "owner": "live",++ "schema": "events/payloads/live.agent_stream.changed.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"}]}nnew file mode 100644@@@ -0,0 +1,52 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/live.agent_stream.changed.v1.json",++ "title": "LiveAgentStreamChangedPayload",++ "description": "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.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "stream_id",++ "kind",++ "at"++ ],++ "properties": {++ "stream_id": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "kind": {++ "enum": [++ "started",++ "ended",++ "visibility",++ "curtain"++ ]++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ],++ "description": "The new visibility, when KIND is visibility."++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ }++ },++ "description": "Whether the privacy screen is up, when KIND is curtain. Never the reason."++ },++ "at": {++ "type": "string",++ "format": "date-time"++ }++ }++}@@@ -90,7 +90,7 @@"on_behalf_of": {"type": "string","pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens."++ "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token."},"act": {"type": "object",nnew file mode 100644@@@ -0,0 +1,39 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/live/agent-stream-create-request.v1.json",++ "title": "LiveAgentStreamCreateRequest",++ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "title",++ "task",++ "visibility"++ ],++ "properties": {++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "agent-stream.v1.json#/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "allow_sites": {++ "type": "array",++ "maxItems": 50,++ "items": {++ "type": "string",++ "format": "uri"++ },++ "description": "The hosts the browser desk may visit. Absent means no limit."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,28 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/live/agent-stream-curtain-request.v1.json",++ "title": "LiveAgentStreamCurtainRequest",++ "description": "live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up",++ "reason"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "reason": {++ "enum": [++ "password_field",++ "secret_file",++ "env_print",++ "manual",++ "site",++ "detector"++ ],++ "description": "Why the curtain is up (the last reason when it comes down)."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/live/agent-stream-publish.v1.json",++ "title": "LiveAgentStreamPublish",++ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "whip_url",++ "ticket",++ "expires_at"++ ],++ "properties": {++ "whip_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "ticket": {++ "type": "string",++ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",++ "description": "The publish ticket, shown once. Live stores only its sha256."++ },++ "expires_at": {++ "type": "string",++ "format": "date-time"++ }++ }++}nnew file mode 100644@@@ -0,0 +1,60 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/live/agent-stream-state.v1.json",++ "title": "LiveAgentStreamState",++ "description": "live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "viewers",++ "encode",++ "curtain",++ "ends_at"++ ],++ "properties": {++ "viewers": {++ "type": "integer",++ "minimum": 0++ },++ "encode": {++ "type": "boolean"++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "reason": {++ "enum": [++ "password_field",++ "secret_file",++ "env_print",++ "manual",++ "site",++ "detector"++ ],++ "description": "Why the curtain is up. The owner's view only; a viewer never sees it."++ }++ }++ },++ "ends_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ }++ }++}nnew file mode 100644@@@ -0,0 +1,185 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/live/agent-stream.v1.json",++ "title": "LiveAgentStream",++ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "channel",++ "title",++ "task",++ "visibility",++ "mode",++ "state",++ "curtain",++ "viewers",++ "started_at",++ "ended_at",++ "worked_seconds",++ "last_frame_url",++ "vod_id",++ "page_url",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent stream's id (ULID, Crockford base32)."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person the stream is theirs."++ },++ "channel": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The owner's Live channel username (the stream's page lives under it)."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "#/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "mode": {++ "enum": [++ "watch",++ "narrated",++ "copilot",++ "chatplays"++ ],++ "description": "How the stream is played. S1 accepts watch only."++ },++ "state": {++ "enum": [++ "idle",++ "live",++ "ended"++ ]++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it went up; absent while it is down."++ }++ }++ },++ "viewers": {++ "type": "integer",++ "minimum": 0++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "worked_seconds": {++ "type": "integer",++ "minimum": 0,++ "description": "How long the agent worked (the card's 'worked 42 min')."++ },++ "last_frame_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."++ },++ "vod_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "Media's id once the recording is stored."++ },++ "page_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://openvibe\\.live/",++ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."++ },++ "label": {++ "const": "AI agent",++ "description": "Always shown, so a viewer knows whose stream this is."++ }++ },++ "$defs": {++ "task": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "source",++ "ref",++ "title"++ ],++ "properties": {++ "source": {++ "enum": [++ "codes",++ "actor",++ "desk",++ "node"++ ],++ "description": "Where the task runs."++ },++ "ref": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The task's id in that source."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The task's page, when it has one."++ }++ }++ }++ }++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ }++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "title": "Fixing the login page",++ "task": {++ "source": "browser",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "private"++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "private"++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "public",++ "allow_sites": [++ "https://example.com"++ ]++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "up": true,++ "reason": "gossip"++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "up": false,++ "reason": "manual"++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "up": true,++ "reason": "password_field"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "whip_url": "https://whip.openvibe.live/whip/agent/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "ticket": "6bIocK6e9t0_61sljsJulmzmWTDyow2zHbGz6ZhOBXg",++ "expires_at": "2026-11-06T16:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "whip_url": "https://whip.openvibe.live/whip/agent/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "ticket": "wpt_6bIocK6e9t0_61sljsJulmzmWTDyow2zHbGz6ZhOBXg",++ "expires_at": "2026-11-06T16:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "viewers": -1,++ "encode": false,++ "curtain": {++ "up": false++ },++ "ends_at": null++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "viewers": 2,++ "encode": true,++ "curtain": {++ "up": false++ },++ "ends_at": null++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "viewers": 0,++ "encode": false,++ "curtain": {++ "up": true,++ "since": "2026-11-06T12:05:00.000Z",++ "reason": "password_field"++ },++ "ends_at": "2026-11-06T13:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "id": "stream_4212",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "channel": "alice",++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "private",++ "mode": "watch",++ "state": "idle",++ "curtain": {++ "up": false++ },++ "viewers": 0,++ "started_at": null,++ "ended_at": null,++ "worked_seconds": 0,++ "last_frame_url": null,++ "vod_id": null,++ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "label": "AI agent"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "channel": "alice",++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "private",++ "mode": "watch",++ "state": "idle",++ "curtain": {++ "up": false++ },++ "viewers": 0,++ "started_at": null,++ "ended_at": null,++ "worked_seconds": 0,++ "last_frame_url": null,++ "vod_id": null,++ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "label": "Stream"++}nnew file mode 100644@@@ -0,0 +1,27 @@++{++ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "channel": "alice",++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "unlisted",++ "mode": "watch",++ "state": "live",++ "curtain": {++ "up": true,++ "since": "2026-11-06T12:05:00.000Z"++ },++ "viewers": 2,++ "started_at": "2026-11-06T12:00:00.000Z",++ "ended_at": null,++ "worked_seconds": 300,++ "last_frame_url": "https://openvibe.live/frames/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ.jpg",++ "vod_id": null,++ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ?k=abcdefghijklmnopqrstuv",++ "label": "AI agent"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "channel": "alice",++ "title": "Fixing the login page",++ "task": {++ "source": "codes",++ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",++ "title": "Fix the login page",++ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"++ },++ "visibility": "private",++ "mode": "watch",++ "state": "idle",++ "curtain": {++ "up": false++ },++ "viewers": 0,++ "started_at": null,++ "ended_at": null,++ "worked_seconds": 0,++ "last_frame_url": null,++ "vod_id": null,++ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "label": "AI agent"++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "kind": "curtain",++ "curtain": {++ "up": true,++ "reason": "password_field"++ },++ "at": "2026-11-06T12:05:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "kind": "curtain",++ "curtain": {++ "up": true++ },++ "at": "2026-11-06T12:05:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "kind": "started",++ "at": "2026-11-06T12:00:00.000Z"++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "kind": "visibility",++ "visibility": "unlisted",++ "at": "2026-11-06T12:10:00.000Z"++}@@@ -275,7 +275,7 @@"on_behalf_of": {"type": "string","pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens."++ "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token."},"act": {"type": "object",@@@ -103355,6 +103355,429 @@}}}++ },++ "live.agent-stream": {++ "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.v1.json",++ "title": "LiveAgentStream",++ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "channel",++ "title",++ "task",++ "visibility",++ "mode",++ "state",++ "curtain",++ "viewers",++ "started_at",++ "ended_at",++ "worked_seconds",++ "last_frame_url",++ "vod_id",++ "page_url",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent stream's id (ULID, Crockford base32)."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person the stream is theirs."++ },++ "channel": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The owner's Live channel username (the stream's page lives under it)."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "#/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "mode": {++ "enum": [++ "watch",++ "narrated",++ "copilot",++ "chatplays"++ ],++ "description": "How the stream is played. S1 accepts watch only."++ },++ "state": {++ "enum": [++ "idle",++ "live",++ "ended"++ ]++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it went up; absent while it is down."++ }++ }++ },++ "viewers": {++ "type": "integer",++ "minimum": 0++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "worked_seconds": {++ "type": "integer",++ "minimum": 0,++ "description": "How long the agent worked (the card's 'worked 42 min')."++ },++ "last_frame_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."++ },++ "vod_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "Media's id once the recording is stored."++ },++ "page_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://openvibe\\.live/",++ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."++ },++ "label": {++ "const": "AI agent",++ "description": "Always shown, so a viewer knows whose stream this is."++ }++ },++ "$defs": {++ "task": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "source",++ "ref",++ "title"++ ],++ "properties": {++ "source": {++ "enum": [++ "codes",++ "actor",++ "desk",++ "node"++ ],++ "description": "Where the task runs."++ },++ "ref": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The task's id in that source."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The task's page, when it has one."++ }++ }++ }++ }++ }++ },++ "live.agent-stream-create-request": {++ "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-create-request.v1.json",++ "title": "LiveAgentStreamCreateRequest",++ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "title",++ "task",++ "visibility"++ ],++ "properties": {++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "agent-stream.v1.json#/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "allow_sites": {++ "type": "array",++ "maxItems": 50,++ "items": {++ "type": "string",++ "format": "uri"++ },++ "description": "The hosts the browser desk may visit. Absent means no limit."++ }++ }++ }++ },++ "live.agent-stream-publish": {++ "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-publish.v1.json",++ "title": "LiveAgentStreamPublish",++ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "whip_url",++ "ticket",++ "expires_at"++ ],++ "properties": {++ "whip_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "ticket": {++ "type": "string",++ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",++ "description": "The publish ticket, shown once. Live stores only its sha256."++ },++ "expires_at": {++ "type": "string",++ "format": "date-time"++ }++ }++ }++ },++ "live.agent-stream-state": {++ "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-state.v1.json",++ "title": "LiveAgentStreamState",++ "description": "live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "viewers",++ "encode",++ "curtain",++ "ends_at"++ ],++ "properties": {++ "viewers": {++ "type": "integer",++ "minimum": 0++ },++ "encode": {++ "type": "boolean"++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "reason": {++ "enum": [++ "password_field",++ "secret_file",++ "env_print",++ "manual",++ "site",++ "detector"++ ],++ "description": "Why the curtain is up. The owner's view only; a viewer never sees it."++ }++ }++ },++ "ends_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ }++ }++ }++ },++ "live.agent-stream-curtain-request": {++ "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-curtain-request.v1.json",++ "title": "LiveAgentStreamCurtainRequest",++ "description": "live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up",++ "reason"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "reason": {++ "enum": [++ "password_field",++ "secret_file",++ "env_print",++ "manual",++ "site",++ "detector"++ ],++ "description": "Why the curtain is up (the last reason when it comes down)."++ }++ }++ }++ },++ "live.agent_stream.changed": {++ "version": "1.0.0",++ "owner": "live",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/live.agent_stream.changed.v1.json",++ "title": "LiveAgentStreamChangedPayload",++ "description": "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.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "stream_id",++ "kind",++ "at"++ ],++ "properties": {++ "stream_id": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "kind": {++ "enum": [++ "started",++ "ended",++ "visibility",++ "curtain"++ ]++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ],++ "description": "The new visibility, when KIND is visibility."++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ }++ },++ "description": "Whether the privacy screen is up, when KIND is curtain. Never the reason."++ },++ "at": {++ "type": "string",++ "format": "date-time"++ }++ }++ }}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.297.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.Codes API",-- "version": "0.297.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"@@@ -124,8 +124,8 @@"service": "live","name": "OpenVibe.Live","origin": "https://openvibe.live",-- "operations": 31,-- "capabilities": 10++ "operations": 38,++ "capabilities": 11},{"service": "media",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Inventory API",-- "version": "0.297.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"@@@ -690,6 +690,532 @@}}},++ "/api/streams/agent": {++ "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.",++ "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"++ }++ }++ }++ },++ "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.",++ "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}/end": {++ "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.",++ "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}/frame": {++ "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.",++ "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}/state": {++ "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.",++ "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}/ticket": {++ "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.",++ "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"++ }++ }++ }++ }++ }++ },++ "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.",++ "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/channel/{username}": {"get": {"operationId": "get_api_streams_channel_username",@@@ -2181,6 +2707,253 @@}}},++ "live.agent-stream-create-request.v1": {++ "title": "LiveAgentStreamCreateRequest",++ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "title",++ "task",++ "visibility"++ ],++ "properties": {++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "allow_sites": {++ "type": "array",++ "maxItems": 50,++ "items": {++ "type": "string",++ "format": "uri"++ },++ "description": "The hosts the browser desk may visit. Absent means no limit."++ }++ }++ },++ "live.agent-stream-publish.v1": {++ "title": "LiveAgentStreamPublish",++ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "whip_url",++ "ticket",++ "expires_at"++ ],++ "properties": {++ "whip_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "ticket": {++ "type": "string",++ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",++ "description": "The publish ticket, shown once. Live stores only its sha256."++ },++ "expires_at": {++ "type": "string",++ "format": "date-time"++ }++ }++ },++ "live.agent-stream.v1": {++ "title": "LiveAgentStream",++ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "channel",++ "title",++ "task",++ "visibility",++ "mode",++ "state",++ "curtain",++ "viewers",++ "started_at",++ "ended_at",++ "worked_seconds",++ "last_frame_url",++ "vod_id",++ "page_url",++ "label"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent stream's id (ULID, Crockford base32)."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person the stream is theirs."++ },++ "channel": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The owner's Live channel username (the stream's page lives under it)."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "task": {++ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"++ },++ "visibility": {++ "enum": [++ "private",++ "unlisted",++ "public"++ ]++ },++ "mode": {++ "enum": [++ "watch",++ "narrated",++ "copilot",++ "chatplays"++ ],++ "description": "How the stream is played. S1 accepts watch only."++ },++ "state": {++ "enum": [++ "idle",++ "live",++ "ended"++ ]++ },++ "curtain": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "up"++ ],++ "properties": {++ "up": {++ "type": "boolean"++ },++ "since": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When it went up; absent while it is down."++ }++ }++ },++ "viewers": {++ "type": "integer",++ "minimum": 0++ },++ "started_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "ended_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "worked_seconds": {++ "type": "integer",++ "minimum": 0,++ "description": "How long the agent worked (the card's 'worked 42 min')."++ },++ "last_frame_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."++ },++ "vod_id": {++ "type": [++ "string",++ "null"++ ],++ "description": "Media's id once the recording is stored."++ },++ "page_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https://openvibe\\.live/",++ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."++ },++ "label": {++ "const": "AI agent",++ "description": "Always shown, so a viewer knows whose stream this is."++ }++ },++ "$defs": {++ "task": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "source",++ "ref",++ "title"++ ],++ "properties": {++ "source": {++ "enum": [++ "codes",++ "actor",++ "desk",++ "node"++ ],++ "description": "Where the task runs."++ },++ "ref": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "The task's id in that source."++ },++ "title": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri",++ "description": "The task's page, when it has one."++ }++ }++ }++ }++ },"live.analytics-read-result.v1": {"title": "LiveAnalyticsReadResult","description": "live.analytics-read-result@1: the answer of GET /internal/analytics-summary?days=1-90 on OpenVibe.Live (capability live.analytics.read): { ok: true, summary } — Live's aggregate traffic totals only, for Network's navigation ordering (which sites are really used), never rows or people. summary is open (it grows with what Live measures). A failure is { ok: false, error }; a caller without the internal key gets 401 { ok: false }.",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.MediaHub API",-- "version": "0.297.0",-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"@@@ -92,7 +92,7 @@ export type ServiceTokenClaims = {*/env?: "sandbox" | "production";/**-- * The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens.++ * The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token.*/on_behalf_of?: string;/**@@@ -292240,3 +292240,167 @@ export interface LockerKeyChange {*/previous_fingerprint?: string;}++++/** [email protected] (owner: live) */++/**++ * live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.++ */++export interface LiveAgentStream {++ /**++ * The agent stream's id (ULID, Crockford base32).++ */++ id: string;++ /**++ * The person the stream is theirs.++ */++ owner: string;++ /**++ * The owner's Live channel username (the stream's page lives under it).++ */++ channel: string;++ title: string;++ task: {++ /**++ * Where the task runs.++ */++ source: "codes" | "actor" | "desk" | "node";++ /**++ * The task's id in that source.++ */++ ref: string;++ title: string;++ /**++ * The task's page, when it has one.++ */++ url?: string | null;++ };++ visibility: "private" | "unlisted" | "public";++ /**++ * How the stream is played. S1 accepts watch only.++ */++ mode: "watch" | "narrated" | "copilot" | "chatplays";++ state: "idle" | "live" | "ended";++ curtain: {++ up: boolean;++ /**++ * When it went up; absent while it is down.++ */++ since?: string | null;++ };++ viewers: number;++ started_at: string | null;++ ended_at: string | null;++ /**++ * How long the agent worked (the card's 'worked 42 min').++ */++ worked_seconds: number;++ /**++ * The last frame the desk sent (JPEG or WebP), or null before the first one.++ */++ last_frame_url: string | null;++ /**++ * Media's id once the recording is stored.++ */++ vod_id: string | null;++ /**++ * The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream).++ */++ page_url: string;++ /**++ * Always shown, so a viewer knows whose stream this is.++ */++ label: "AI agent";++}++++/** [email protected] (owner: live) */++/**++ * live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).++ */++export interface LiveAgentStreamCreateRequest {++ title: string;++ task: {++ /**++ * Where the task runs.++ */++ source: "codes" | "actor" | "desk" | "node";++ /**++ * The task's id in that source.++ */++ ref: string;++ title: string;++ /**++ * The task's page, when it has one.++ */++ url?: string | null;++ };++ visibility: "private" | "unlisted" | "public";++ /**++ * The hosts the browser desk may visit. Absent means no limit.++ *++ * @maxItems 50++ */++ allow_sites?: string[];++}++++/** [email protected] (owner: live) */++/**++ * live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.++ */++export interface LiveAgentStreamPublish {++ whip_url: string;++ /**++ * The publish ticket, shown once. Live stores only its sha256.++ */++ ticket: string;++ expires_at: string;++}++++/** [email protected] (owner: live) */++/**++ * live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.++ */++export interface LiveAgentStreamState {++ viewers: number;++ encode: boolean;++ curtain: {++ up: boolean;++ since?: string | null;++ /**++ * Why the curtain is up. The owner's view only; a viewer never sees it.++ */++ reason?: "password_field" | "secret_file" | "env_print" | "manual" | "site" | "detector";++ };++ ends_at: string | null;++}++++/** [email protected] (owner: live) */++/**++ * live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.++ */++export interface LiveAgentStreamCurtainRequest {++ up: boolean;++ /**++ * Why the curtain is up (the last reason when it comes down).++ */++ reason: "password_field" | "secret_file" | "env_print" | "manual" | "site" | "detector";++}++++/** [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.++ */++export interface LiveAgentStreamChangedPayload {++ stream_id: string;++ kind: "started" | "ended" | "visibility" | "curtain";++ /**++ * The new visibility, when KIND is visibility.++ */++ visibility?: "private" | "unlisted" | "public";++ /**++ * Whether the privacy screen is up, when KIND is curtain. Never the reason.++ */++ curtain?: {++ up: boolean;++ };++ at: string;++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "id": "live.agent_stream.publish",++ "version": "1.0",++ "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.",++ "inputSchema": "live.agent-stream-create-request@1",++ "outputSchema": "live.agent-stream-publish@1",++ "permissions": [++ "live:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "standard",++ "events": [++ "live.agent_stream.changed"++ ],++ "implementedBy": [++ "POST /api/streams/agent",++ "POST /api/streams/agent/:id/ticket",++ "DELETE /api/streams/agent/:id/ticket",++ "POST /api/streams/agent/:id/curtain",++ "PUT /api/streams/agent/:id/frame",++ "POST /api/streams/agent/:id/end",++ "GET /api/streams/agent/:id/state"++ ],++ "sensitive": true++}@@@ -47,6 +47,7 @@"neighbourhood": "streams"},"capabilities": [++ "live.agent_stream.publish","live.analytics.read","live.avatar.write","live.openre.slot.bind",@@@ -62,6 +63,7 @@"live.url_registry.refresh"],"eventsProduced": [++ "live.agent_stream.changed","live.index_document.deleted","live.index_document.upserted","live.moderation.action",@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.297.0",++ "version": "0.298.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.297.0",++ "version": "0.298.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.297.0",++ "version": "0.298.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,8 +1,16 @@
@@ -1,8 +1,16 @@
# Changelog
# Changelog
+## 0.298.0 — 2026-11-06
+
+- Add `live.agent-stream@1`: an agent's own stream on OpenVibe.Live (the Agent Streams plan, S1). It is a `managed_streams` row of kind `agent` with an `ags_<ULID>` id, no stream key and no normal slot; it carries the owner, the channel, the task it is doing (`codes`, `actor`, `desk` or `node`), the visibility (`private`, `unlisted`, `public`), the mode (`watch` in S1), the state, the curtain, the viewers, the worked seconds, the last frame, the VOD and the page. The card stays after the stream ends.
+- Add the four request/result schemas: `live.agent-stream-create-request@1` (title, task, visibility, the optional `allow_sites`), `live.agent-stream-publish@1` (`whip_url`, the one-time publish ticket `wpt_…`, `expires_at`), `live.agent-stream-state@1` (viewers, `encode`, the curtain and `ends_at`, what the desk polls) and `live.agent-stream-curtain-request@1` (`up` and the reason).
+- Add the event `live.agent_stream.changed` (`started`, `ended`, `visibility`, `curtain`, never the reason) and the capability `live.agent_stream.publish`, and name both in Live's service manifest. The stream's contract ids keep the design's hyphen (`live.agent-stream@1`); the capability and the event type carry an underscore because `identity.service-token-claims@1`'s `cap` pattern and `events.event-envelope@1`'s `event_type` pattern allow letters, digits and underscores only. The capability's description records the design's `live.agent-stream.publish` name and why it is written `live.agent_stream.publish`. `identity.service-token-claims@1`'s `on_behalf_of` description now says a node token names its owner on the audience where the machine acts for them (Live's), so a receiver knows where to read the stream's owner.
+- Valid and invalid fixtures cover the stream, the create request, the publish part, the state, the curtain request and the event payload, so a missing field, a bad id or a reason outside the list fails the run.
+
## 0.297.0 — 2026-11-06
## 0.297.0 — 2026-11-06
- Add `identity.subject-assertion-claims@1`: the claims of a short-lived ES256 assertion signed by OpenVibe.Network that says a person allowed one service to act for them on another service — `sub` (the person), `aud` (the service it is for), `act` (the service it was minted for), optionally `for` (the services that may carry it), `jti`, `iat`, `exp`. Network mints one only from the person's own access token (`POST /internal/subject-assertions`), so a service that merely knows a person's id cannot say the person allowed anything; the key is published in Network's JWKS (`kid ov-network-assertion-1`). The money routes of Billing and Tips check it against the person they act for, and refuse the old "the service vouches for its person" way once `BILLING_REQUIRE_SUBJECT_ASSERTION` / `TIPS_REQUIRE_SUBJECT_ASSERTION` is on. Only a service token Network issued for its own API (`openvibe.network`) mints one. See the ADR-003 amendment of 2026-11-06.
- Add `identity.subject-assertion-claims@1`: the claims of a short-lived ES256 assertion signed by OpenVibe.Network that says a person allowed one service to act for them on another service — `sub` (the person), `aud` (the service it is for), `act` (the service it was minted for), optionally `for` (the services that may carry it), `jti`, `iat`, `exp`. Network mints one only from the person's own access token (`POST /internal/subject-assertions`), so a service that merely knows a person's id cannot say the person allowed anything; the key is published in Network's JWKS (`kid ov-network-assertion-1`). The money routes of Billing and Tips check it against the person they act for, and refuse the old "the service vouches for its person" way once `BILLING_REQUIRE_SUBJECT_ASSERTION` / `TIPS_REQUIRE_SUBJECT_ASSERTION` is on. Only a service token Network issued for its own API (`openvibe.network`) mints one. See the ADR-003 amendment of 2026-11-06.
+
## 0.296.0 — 2026-11-06
## 0.296.0 — 2026-11-06
- Sharing learns locked items. `share.update-request@1` gains `envelope`: a `locker.envelope@1`, base64, the content re-sealed for the people who stay, sent with the members that remain when someone is removed from a people-locked item. The service stores it before it drops the member; it never opens it.
- Sharing learns locked items. `share.update-request@1` gains `envelope`: a `locker.envelope@1`, base64, the content re-sealed for the people who stay, sent with the members that remain when someone is removed from a people-locked item. The service stores it before it drops the member; it never opens it.
@@ -9402,6 +9402,60 @@
@@ -9402,6 +9402,60 @@
"visibility": "public",
"visibility": "public",
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
+ },
+ {
+ "id": "live.agent-stream",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent-stream-create-request",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream-create-request.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent-stream-publish",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream-publish.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent-stream-state",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream-state.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent-stream-curtain-request",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "live/agent-stream-curtain-request.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "live.agent_stream.changed",
+ "version": "1.0.0",
+ "owner": "live",
+ "schema": "events/payloads/live.agent_stream.changed.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
}
}
]
]
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/live.agent_stream.changed.v1.json",
+ "title": "LiveAgentStreamChangedPayload",
+ "description": "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.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "stream_id",
+ "kind",
+ "at"
+ ],
+ "properties": {
+ "stream_id": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "kind": {
+ "enum": [
+ "started",
+ "ended",
+ "visibility",
+ "curtain"
+ ]
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ],
+ "description": "The new visibility, when KIND is visibility."
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ }
+ },
+ "description": "Whether the privacy screen is up, when KIND is curtain. Never the reason."
+ },
+ "at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+}
@@ -90,7 +90,7 @@
@@ -90,7 +90,7 @@
"on_behalf_of": {
"on_behalf_of": {
"type": "string",
"type": "string",
"pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
"pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens."
+ "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token."
},
},
"act": {
"act": {
"type": "object",
"type": "object",
new file mode 100644
new file mode 100644
@@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/live/agent-stream-create-request.v1.json",
+ "title": "LiveAgentStreamCreateRequest",
+ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "title",
+ "task",
+ "visibility"
+ ],
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "agent-stream.v1.json#/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "allow_sites": {
+ "type": "array",
+ "maxItems": 50,
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "description": "The hosts the browser desk may visit. Absent means no limit."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/live/agent-stream-curtain-request.v1.json",
+ "title": "LiveAgentStreamCurtainRequest",
+ "description": "live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up",
+ "reason"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "reason": {
+ "enum": [
+ "password_field",
+ "secret_file",
+ "env_print",
+ "manual",
+ "site",
+ "detector"
+ ],
+ "description": "Why the curtain is up (the last reason when it comes down)."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/live/agent-stream-publish.v1.json",
+ "title": "LiveAgentStreamPublish",
+ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "whip_url",
+ "ticket",
+ "expires_at"
+ ],
+ "properties": {
+ "whip_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "ticket": {
+ "type": "string",
+ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",
+ "description": "The publish ticket, shown once. Live stores only its sha256."
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/live/agent-stream-state.v1.json",
+ "title": "LiveAgentStreamState",
+ "description": "live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "viewers",
+ "encode",
+ "curtain",
+ "ends_at"
+ ],
+ "properties": {
+ "viewers": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "encode": {
+ "type": "boolean"
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "reason": {
+ "enum": [
+ "password_field",
+ "secret_file",
+ "env_print",
+ "manual",
+ "site",
+ "detector"
+ ],
+ "description": "Why the curtain is up. The owner's view only; a viewer never sees it."
+ }
+ }
+ },
+ "ends_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,185 @@
@@ -0,0 +1,185 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/live/agent-stream.v1.json",
+ "title": "LiveAgentStream",
+ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "channel",
+ "title",
+ "task",
+ "visibility",
+ "mode",
+ "state",
+ "curtain",
+ "viewers",
+ "started_at",
+ "ended_at",
+ "worked_seconds",
+ "last_frame_url",
+ "vod_id",
+ "page_url",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent stream's id (ULID, Crockford base32)."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person the stream is theirs."
+ },
+ "channel": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The owner's Live channel username (the stream's page lives under it)."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "#/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "mode": {
+ "enum": [
+ "watch",
+ "narrated",
+ "copilot",
+ "chatplays"
+ ],
+ "description": "How the stream is played. S1 accepts watch only."
+ },
+ "state": {
+ "enum": [
+ "idle",
+ "live",
+ "ended"
+ ]
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it went up; absent while it is down."
+ }
+ }
+ },
+ "viewers": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "worked_seconds": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How long the agent worked (the card's 'worked 42 min')."
+ },
+ "last_frame_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."
+ },
+ "vod_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Media's id once the recording is stored."
+ },
+ "page_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://openvibe\\.live/",
+ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."
+ },
+ "label": {
+ "const": "AI agent",
+ "description": "Always shown, so a viewer knows whose stream this is."
+ }
+ },
+ "$defs": {
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "source",
+ "ref",
+ "title"
+ ],
+ "properties": {
+ "source": {
+ "enum": [
+ "codes",
+ "actor",
+ "desk",
+ "node"
+ ],
+ "description": "Where the task runs."
+ },
+ "ref": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The task's id in that source."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The task's page, when it has one."
+ }
+ }
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "title": "Fixing the login page",
+ "task": {
+ "source": "browser",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "private"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "private"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "public",
+ "allow_sites": [
+ "https://example.com"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "up": true,
+ "reason": "gossip"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "up": false,
+ "reason": "manual"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "up": true,
+ "reason": "password_field"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "whip_url": "https://whip.openvibe.live/whip/agent/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "ticket": "6bIocK6e9t0_61sljsJulmzmWTDyow2zHbGz6ZhOBXg",
+ "expires_at": "2026-11-06T16:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "whip_url": "https://whip.openvibe.live/whip/agent/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "ticket": "wpt_6bIocK6e9t0_61sljsJulmzmWTDyow2zHbGz6ZhOBXg",
+ "expires_at": "2026-11-06T16:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "viewers": -1,
+ "encode": false,
+ "curtain": {
+ "up": false
+ },
+ "ends_at": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "viewers": 2,
+ "encode": true,
+ "curtain": {
+ "up": false
+ },
+ "ends_at": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "viewers": 0,
+ "encode": false,
+ "curtain": {
+ "up": true,
+ "since": "2026-11-06T12:05:00.000Z",
+ "reason": "password_field"
+ },
+ "ends_at": "2026-11-06T13:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "id": "stream_4212",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "channel": "alice",
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "private",
+ "mode": "watch",
+ "state": "idle",
+ "curtain": {
+ "up": false
+ },
+ "viewers": 0,
+ "started_at": null,
+ "ended_at": null,
+ "worked_seconds": 0,
+ "last_frame_url": null,
+ "vod_id": null,
+ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "label": "AI agent"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "channel": "alice",
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "private",
+ "mode": "watch",
+ "state": "idle",
+ "curtain": {
+ "up": false
+ },
+ "viewers": 0,
+ "started_at": null,
+ "ended_at": null,
+ "worked_seconds": 0,
+ "last_frame_url": null,
+ "vod_id": null,
+ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "label": "Stream"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
+{
+ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "channel": "alice",
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "unlisted",
+ "mode": "watch",
+ "state": "live",
+ "curtain": {
+ "up": true,
+ "since": "2026-11-06T12:05:00.000Z"
+ },
+ "viewers": 2,
+ "started_at": "2026-11-06T12:00:00.000Z",
+ "ended_at": null,
+ "worked_seconds": 300,
+ "last_frame_url": "https://openvibe.live/frames/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ.jpg",
+ "vod_id": null,
+ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ?k=abcdefghijklmnopqrstuv",
+ "label": "AI agent"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "channel": "alice",
+ "title": "Fixing the login page",
+ "task": {
+ "source": "codes",
+ "ref": "task_01JAB2C3D4E5F6G7H8J9K0MNP",
+ "title": "Fix the login page",
+ "url": "https://codes.openvibe.live/tasks/task_01JAB2C3D4E5F6G7H8J9K0MNP"
+ },
+ "visibility": "private",
+ "mode": "watch",
+ "state": "idle",
+ "curtain": {
+ "up": false
+ },
+ "viewers": 0,
+ "started_at": null,
+ "ended_at": null,
+ "worked_seconds": 0,
+ "last_frame_url": null,
+ "vod_id": null,
+ "page_url": "https://openvibe.live/@alice/agents/ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "label": "AI agent"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "kind": "curtain",
+ "curtain": {
+ "up": true,
+ "reason": "password_field"
+ },
+ "at": "2026-11-06T12:05:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "kind": "curtain",
+ "curtain": {
+ "up": true
+ },
+ "at": "2026-11-06T12:05:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "kind": "started",
+ "at": "2026-11-06T12:00:00.000Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "kind": "visibility",
+ "visibility": "unlisted",
+ "at": "2026-11-06T12:10:00.000Z"
+}
@@ -275,7 +275,7 @@
@@ -275,7 +275,7 @@
"on_behalf_of": {
"on_behalf_of": {
"type": "string",
"type": "string",
"pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
"pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens."
+ "description": "The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token."
},
},
"act": {
"act": {
"type": "object",
"type": "object",
@@ -103355,6 +103355,429 @@
@@ -103355,6 +103355,429 @@
}
}
}
}
}
}
+ },
+ "live.agent-stream": {
+ "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.v1.json",
+ "title": "LiveAgentStream",
+ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "channel",
+ "title",
+ "task",
+ "visibility",
+ "mode",
+ "state",
+ "curtain",
+ "viewers",
+ "started_at",
+ "ended_at",
+ "worked_seconds",
+ "last_frame_url",
+ "vod_id",
+ "page_url",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent stream's id (ULID, Crockford base32)."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person the stream is theirs."
+ },
+ "channel": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The owner's Live channel username (the stream's page lives under it)."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "#/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "mode": {
+ "enum": [
+ "watch",
+ "narrated",
+ "copilot",
+ "chatplays"
+ ],
+ "description": "How the stream is played. S1 accepts watch only."
+ },
+ "state": {
+ "enum": [
+ "idle",
+ "live",
+ "ended"
+ ]
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it went up; absent while it is down."
+ }
+ }
+ },
+ "viewers": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "worked_seconds": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How long the agent worked (the card's 'worked 42 min')."
+ },
+ "last_frame_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."
+ },
+ "vod_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Media's id once the recording is stored."
+ },
+ "page_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://openvibe\\.live/",
+ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."
+ },
+ "label": {
+ "const": "AI agent",
+ "description": "Always shown, so a viewer knows whose stream this is."
+ }
+ },
+ "$defs": {
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "source",
+ "ref",
+ "title"
+ ],
+ "properties": {
+ "source": {
+ "enum": [
+ "codes",
+ "actor",
+ "desk",
+ "node"
+ ],
+ "description": "Where the task runs."
+ },
+ "ref": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The task's id in that source."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The task's page, when it has one."
+ }
+ }
+ }
+ }
+ }
+ },
+ "live.agent-stream-create-request": {
+ "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-create-request.v1.json",
+ "title": "LiveAgentStreamCreateRequest",
+ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "title",
+ "task",
+ "visibility"
+ ],
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "agent-stream.v1.json#/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "allow_sites": {
+ "type": "array",
+ "maxItems": 50,
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "description": "The hosts the browser desk may visit. Absent means no limit."
+ }
+ }
+ }
+ },
+ "live.agent-stream-publish": {
+ "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-publish.v1.json",
+ "title": "LiveAgentStreamPublish",
+ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "whip_url",
+ "ticket",
+ "expires_at"
+ ],
+ "properties": {
+ "whip_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "ticket": {
+ "type": "string",
+ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",
+ "description": "The publish ticket, shown once. Live stores only its sha256."
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ }
+ },
+ "live.agent-stream-state": {
+ "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-state.v1.json",
+ "title": "LiveAgentStreamState",
+ "description": "live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "viewers",
+ "encode",
+ "curtain",
+ "ends_at"
+ ],
+ "properties": {
+ "viewers": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "encode": {
+ "type": "boolean"
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "reason": {
+ "enum": [
+ "password_field",
+ "secret_file",
+ "env_print",
+ "manual",
+ "site",
+ "detector"
+ ],
+ "description": "Why the curtain is up. The owner's view only; a viewer never sees it."
+ }
+ }
+ },
+ "ends_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ }
+ }
+ }
+ },
+ "live.agent-stream-curtain-request": {
+ "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-curtain-request.v1.json",
+ "title": "LiveAgentStreamCurtainRequest",
+ "description": "live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up",
+ "reason"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "reason": {
+ "enum": [
+ "password_field",
+ "secret_file",
+ "env_print",
+ "manual",
+ "site",
+ "detector"
+ ],
+ "description": "Why the curtain is up (the last reason when it comes down)."
+ }
+ }
+ }
+ },
+ "live.agent_stream.changed": {
+ "version": "1.0.0",
+ "owner": "live",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/live.agent_stream.changed.v1.json",
+ "title": "LiveAgentStreamChangedPayload",
+ "description": "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.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "stream_id",
+ "kind",
+ "at"
+ ],
+ "properties": {
+ "stream_id": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "kind": {
+ "enum": [
+ "started",
+ "ended",
+ "visibility",
+ "curtain"
+ ]
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ],
+ "description": "The new visibility, when KIND is visibility."
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ }
+ },
+ "description": "Whether the privacy screen is up, when KIND is curtain. Never the reason."
+ },
+ "at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ }
}
}
}
}
}
}
@@ -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.297.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.297.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"
@@ -124,8 +124,8 @@
@@ -124,8 +124,8 @@
"service": "live",
"service": "live",
"name": "OpenVibe.Live",
"name": "OpenVibe.Live",
"origin": "https://openvibe.live",
"origin": "https://openvibe.live",
- "operations": 31,
- "capabilities": 10
+ "operations": 38,
+ "capabilities": 11
},
},
{
{
"service": "media",
"service": "media",
@@ -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.297.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"
@@ -690,6 +690,532 @@
@@ -690,6 +690,532 @@
}
}
}
}
},
},
+ "/api/streams/agent": {
+ "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.",
+ "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"
+ }
+ }
+ }
+ },
+ "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.",
+ "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}/end": {
+ "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.",
+ "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}/frame": {
+ "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.",
+ "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}/state": {
+ "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.",
+ "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}/ticket": {
+ "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.",
+ "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"
+ }
+ }
+ }
+ }
+ }
+ },
+ "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.",
+ "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/channel/{username}": {
"/api/streams/channel/{username}": {
"get": {
"get": {
"operationId": "get_api_streams_channel_username",
"operationId": "get_api_streams_channel_username",
@@ -2181,6 +2707,253 @@
@@ -2181,6 +2707,253 @@
}
}
}
}
},
},
+ "live.agent-stream-create-request.v1": {
+ "title": "LiveAgentStreamCreateRequest",
+ "description": "live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "title",
+ "task",
+ "visibility"
+ ],
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "allow_sites": {
+ "type": "array",
+ "maxItems": 50,
+ "items": {
+ "type": "string",
+ "format": "uri"
+ },
+ "description": "The hosts the browser desk may visit. Absent means no limit."
+ }
+ }
+ },
+ "live.agent-stream-publish.v1": {
+ "title": "LiveAgentStreamPublish",
+ "description": "live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "whip_url",
+ "ticket",
+ "expires_at"
+ ],
+ "properties": {
+ "whip_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://whip\\.openvibe\\.live/whip/agent/ags_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "ticket": {
+ "type": "string",
+ "pattern": "^wpt_[A-Za-z0-9_-]{43}$",
+ "description": "The publish ticket, shown once. Live stores only its sha256."
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "live.agent-stream.v1": {
+ "title": "LiveAgentStream",
+ "description": "live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "channel",
+ "title",
+ "task",
+ "visibility",
+ "mode",
+ "state",
+ "curtain",
+ "viewers",
+ "started_at",
+ "ended_at",
+ "worked_seconds",
+ "last_frame_url",
+ "vod_id",
+ "page_url",
+ "label"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent stream's id (ULID, Crockford base32)."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person the stream is theirs."
+ },
+ "channel": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The owner's Live channel username (the stream's page lives under it)."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "task": {
+ "$ref": "#/components/schemas/live.agent-stream.v1/$defs/task"
+ },
+ "visibility": {
+ "enum": [
+ "private",
+ "unlisted",
+ "public"
+ ]
+ },
+ "mode": {
+ "enum": [
+ "watch",
+ "narrated",
+ "copilot",
+ "chatplays"
+ ],
+ "description": "How the stream is played. S1 accepts watch only."
+ },
+ "state": {
+ "enum": [
+ "idle",
+ "live",
+ "ended"
+ ]
+ },
+ "curtain": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "up"
+ ],
+ "properties": {
+ "up": {
+ "type": "boolean"
+ },
+ "since": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When it went up; absent while it is down."
+ }
+ }
+ },
+ "viewers": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "started_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "ended_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "worked_seconds": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "How long the agent worked (the card's 'worked 42 min')."
+ },
+ "last_frame_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The last frame the desk sent (JPEG or WebP), or null before the first one."
+ },
+ "vod_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Media's id once the recording is stored."
+ },
+ "page_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https://openvibe\\.live/",
+ "description": "The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream)."
+ },
+ "label": {
+ "const": "AI agent",
+ "description": "Always shown, so a viewer knows whose stream this is."
+ }
+ },
+ "$defs": {
+ "task": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "source",
+ "ref",
+ "title"
+ ],
+ "properties": {
+ "source": {
+ "enum": [
+ "codes",
+ "actor",
+ "desk",
+ "node"
+ ],
+ "description": "Where the task runs."
+ },
+ "ref": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The task's id in that source."
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri",
+ "description": "The task's page, when it has one."
+ }
+ }
+ }
+ }
+ },
"live.analytics-read-result.v1": {
"live.analytics-read-result.v1": {
"title": "LiveAnalyticsReadResult",
"title": "LiveAnalyticsReadResult",
"description": "live.analytics-read-result@1: the answer of GET /internal/analytics-summary?days=1-90 on OpenVibe.Live (capability live.analytics.read): { ok: true, summary } — Live's aggregate traffic totals only, for Network's navigation ordering (which sites are really used), never rows or people. summary is open (it grows with what Live measures). A failure is { ok: false, error }; a caller without the internal key gets 401 { ok: false }.",
"description": "live.analytics-read-result@1: the answer of GET /internal/analytics-summary?days=1-90 on OpenVibe.Live (capability live.analytics.read): { ok: true, summary } — Live's aggregate traffic totals only, for Network's navigation ordering (which sites are really used), never rows or people. summary is open (it grows with what Live measures). A failure is { ok: false, error }; a caller without the internal key 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.MediaHub API",
"title": "OpenVibe.MediaHub API",
- "version": "0.297.0",
- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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.297.0",
- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.297.0): each operation lists the capabilities it performs; a token for 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.298.0",
+ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.298.0): each operation lists the capabilities it performs; a token for 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"
@@ -92,7 +92,7 @@ export type ServiceTokenClaims = {
@@ -92,7 +92,7 @@ export type ServiceTokenClaims = {
*/
*/
env?: "sandbox" | "production";
env?: "sandbox" | "production";
/**
/**
- * The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens.
+ * The person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Also present on a node token that asks for an audience where the machine acts for its owner (Agent Streams S1: openvibe.live and live.agent_stream.publish); absent on every other client_credentials token.
*/
*/
on_behalf_of?: string;
on_behalf_of?: string;
/**
/**
@@ -292240,3 +292240,167 @@ export interface LockerKeyChange {
@@ -292240,3 +292240,167 @@ export interface LockerKeyChange {
*/
*/
previous_fingerprint?: string;
previous_fingerprint?: string;
}
}
+
+/** [email protected] (owner: live) */
+/**
+ * live.agent-stream@1 (the Agent Streams plan, S1): an agent's own stream on OpenVibe.Live. It is a managed_streams row of kind 'agent' with the id ags_<ULID>; it never has a stream key and it never takes a normal slot (a second live one answers 409 live.agent_stream_limit). OWNER is the person the stream belongs to, CHANNEL their Live channel, and TASK says what the agent is doing and where that task lives. VISIBILITY is who may watch; MODE is how the stream is played (S1 accepts watch only) and STATE where it stands. CURTAIN is the desk's privacy screen: while it is up Live pauses every viewer's consumer, so a viewer sees 'Private screen' and never the reason (the reason stays in the owner's view). The card stays after the stream ends, with the last frame, the worked seconds and the VOD once it is recorded.
+ */
+export interface LiveAgentStream {
+ /**
+ * The agent stream's id (ULID, Crockford base32).
+ */
+ id: string;
+ /**
+ * The person the stream is theirs.
+ */
+ owner: string;
+ /**
+ * The owner's Live channel username (the stream's page lives under it).
+ */
+ channel: string;
+ title: string;
+ task: {
+ /**
+ * Where the task runs.
+ */
+ source: "codes" | "actor" | "desk" | "node";
+ /**
+ * The task's id in that source.
+ */
+ ref: string;
+ title: string;
+ /**
+ * The task's page, when it has one.
+ */
+ url?: string | null;
+ };
+ visibility: "private" | "unlisted" | "public";
+ /**
+ * How the stream is played. S1 accepts watch only.
+ */
+ mode: "watch" | "narrated" | "copilot" | "chatplays";
+ state: "idle" | "live" | "ended";
+ curtain: {
+ up: boolean;
+ /**
+ * When it went up; absent while it is down.
+ */
+ since?: string | null;
+ };
+ viewers: number;
+ started_at: string | null;
+ ended_at: string | null;
+ /**
+ * How long the agent worked (the card's 'worked 42 min').
+ */
+ worked_seconds: number;
+ /**
+ * The last frame the desk sent (JPEG or WebP), or null before the first one.
+ */
+ last_frame_url: string | null;
+ /**
+ * Media's id once the recording is stored.
+ */
+ vod_id: string | null;
+ /**
+ * The owner's page, /@person/agents/<ags_id> (with ?k= for the owner of an unlisted stream).
+ */
+ page_url: string;
+ /**
+ * Always shown, so a viewer knows whose stream this is.
+ */
+ label: "AI agent";
+}
+
+/** [email protected] (owner: live) */
+/**
+ * live.agent-stream-create-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent on OpenVibe.Live (capability live.agent_stream.publish). It answers 201 with the stream (live.agent-stream@1) and the publish part (live.agent-stream-publish@1): { stream, publish }. 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 live.agent_stream.publish for the audience openvibe.live; Network grants it to exactly those principals. Never a developer-app token, never another person's stream. TITLE is the card's title, TASK says what the agent is doing and where that task lives, VISIBILITY says who may watch, and ALLOW_SITES is the optional list of hosts a browser desk may navigate to (a desk that leaves the list raises the curtain).
+ */
+export interface LiveAgentStreamCreateRequest {
+ title: string;
+ task: {
+ /**
+ * Where the task runs.
+ */
+ source: "codes" | "actor" | "desk" | "node";
+ /**
+ * The task's id in that source.
+ */
+ ref: string;
+ title: string;
+ /**
+ * The task's page, when it has one.
+ */
+ url?: string | null;
+ };
+ visibility: "private" | "unlisted" | "public";
+ /**
+ * The hosts the browser desk may visit. Absent means no limit.
+ *
+ * @maxItems 50
+ */
+ allow_sites?: string[];
+}
+
+/** [email protected] (owner: live) */
+/**
+ * live.agent-stream-publish@1 (the Agent Streams plan, S1): the publish part of the answer to POST /api/streams/agent (beside the stream, live.agent-stream@1). WHIP_URL is where the desk publishes, TICKET is the publish ticket (wpt_ plus 32 random bytes, base64url; Live keeps only its sha256, it is bound to this stream, this person and one WHIP session, and it lives four hours), and EXPIRES_AT is when the ticket dies. The desk sends the ticket as Authorization: Bearer wpt_… on POST /whip/agent/:id. A ticket that does not match, has expired or names another stream answers 401 invalid_ticket; a second WHIP session while one is up answers 409 already_publishing. POST /api/streams/agent/:id/ticket renews the ticket (the desk renews at three hours) and DELETE /api/streams/agent/:id/ticket revokes it: that is the kill switch, and Live ends the WHIP session at once.
+ */
+export interface LiveAgentStreamPublish {
+ whip_url: string;
+ /**
+ * The publish ticket, shown once. Live stores only its sha256.
+ */
+ ticket: string;
+ expires_at: string;
+}
+
+/** [email protected] (owner: live) */
+/**
+ * live.agent-stream-state@1 (the Agent Streams plan, S1): what the desk reads every ten seconds, GET /api/streams/agent/:id/state on OpenVibe.Live (with the publish ticket). VIEWERS is how many people watch. ENCODE says whether Live wants video: it is true while anyone watches or the stream is public, and while it is false the desk stops encoding and sends a snapshot every five seconds (PUT /api/streams/agent/:id/frame, JPEG or WebP, at most 200 KB, with the ticket). CURTAIN is the desk's privacy screen (the reason is the owner's only). ENDS_AT is when the stream ends.
+ */
+export interface LiveAgentStreamState {
+ viewers: number;
+ encode: boolean;
+ curtain: {
+ up: boolean;
+ since?: string | null;
+ /**
+ * Why the curtain is up. The owner's view only; a viewer never sees it.
+ */
+ reason?: "password_field" | "secret_file" | "env_print" | "manual" | "site" | "detector";
+ };
+ ends_at: string | null;
+}
+
+/** [email protected] (owner: live) */
+/**
+ * live.agent-stream-curtain-request@1 (the Agent Streams plan, S1): the body of POST /api/streams/agent/:id/curtain on OpenVibe.Live (capability live.agent_stream.publish): the desk reports that its privacy screen went up or came down. While the curtain is up Live pauses every viewer's consumer (mediasoup consumer.pause()), so a desk that failed to blank still shows nothing. Viewers see 'Private screen' and never why. The curtain comes down only from the desk, after its detectors report clear for two seconds, or from the owner's own button; a detector that fails or is unsure puts it up and never down.
+ */
+export interface LiveAgentStreamCurtainRequest {
+ up: boolean;
+ /**
+ * Why the curtain is up (the last reason when it comes down).
+ */
+ reason: "password_field" | "secret_file" | "env_print" | "manual" | "site" | "detector";
+}
+
+/** [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.
+ */
+export interface LiveAgentStreamChangedPayload {
+ stream_id: string;
+ kind: "started" | "ended" | "visibility" | "curtain";
+ /**
+ * The new visibility, when KIND is visibility.
+ */
+ visibility?: "private" | "unlisted" | "public";
+ /**
+ * Whether the privacy screen is up, when KIND is curtain. Never the reason.
+ */
+ curtain?: {
+ up: boolean;
+ };
+ at: string;
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "id": "live.agent_stream.publish",
+ "version": "1.0",
+ "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.",
+ "inputSchema": "live.agent-stream-create-request@1",
+ "outputSchema": "live.agent-stream-publish@1",
+ "permissions": [
+ "live:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "standard",
+ "events": [
+ "live.agent_stream.changed"
+ ],
+ "implementedBy": [
+ "POST /api/streams/agent",
+ "POST /api/streams/agent/:id/ticket",
+ "DELETE /api/streams/agent/:id/ticket",
+ "POST /api/streams/agent/:id/curtain",
+ "PUT /api/streams/agent/:id/frame",
+ "POST /api/streams/agent/:id/end",
+ "GET /api/streams/agent/:id/state"
+ ],
+ "sensitive": true
+}
@@ -47,6 +47,7 @@
@@ -47,6 +47,7 @@
"neighbourhood": "streams"
"neighbourhood": "streams"
},
},
"capabilities": [
"capabilities": [
+ "live.agent_stream.publish",
"live.analytics.read",
"live.analytics.read",
"live.avatar.write",
"live.avatar.write",
"live.openre.slot.bind",
"live.openre.slot.bind",
@@ -62,6 +63,7 @@
@@ -62,6 +63,7 @@
"live.url_registry.refresh"
"live.url_registry.refresh"
],
],
"eventsProduced": [
"eventsProduced": [
+ "live.agent_stream.changed",
"live.index_document.deleted",
"live.index_document.deleted",
"live.index_document.upserted",
"live.index_document.upserted",
"live.moderation.action",
"live.moderation.action",
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.297.0",
+ "version": "0.298.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.297.0",
+ "version": "0.298.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.297.0",
+ "version": "0.298.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",