LiveAgentStreamState live.agent-stream-state@2
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 2.0.0
- Owner
- live
- Visibility
- first-party
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/live/agent-stream-state.v2.json
live.agent-stream-state@2 (the Agent Streams plan, S4): 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 privacy screen (the reason is the owner only). ENDS_AT is when the stream ends. LINES are the lines the agent said, oldest first, each with its id: the desk asks for the lines after the last id it spoke (the ?after parameter) and speaks them in the person own voice. VOICE is the voice the agent speaks in (the mode, the personality, the voice, the mute and, when the person allowance ran out, the pause message). The v2 shape adds LINES and VOICE to the v1 shape (both optional, so a v1 reader keeps working); the v1 fields keep their meaning. CAPTIONS_URL is where the recording captions live: the WebVTT a VOD player can attach as a text track.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
viewers | integer | yes |
| |
encode | boolean | yes | ||
curtain | object | yes |
| |
curtain.up | boolean | yes | ||
curtain.since | string | null |
| ||
curtain.reason | enum | Why the curtain is up. The owner view only; a viewer never sees it. The password_field reason is the one that silences the agent voice: a line spoken over a password field would put words where a secret is. |
| |
ends_at | string | null | yes |
| |
lines | array of object | The lines the agent said, oldest first. The desk asks for the lines after the last id it spoke. |
| |
lines[].id | integer | yes | The line id: the desk cursor. | |
lines[].at | string | yes |
| |
lines[].text | string | yes | The line, at most 220 characters. It passed the house text filters before it was written. |
|
lines[].kind | enum | yes | What the line is about: a step that started, a step that failed, a result that landed, or an idle line. |
|
lines[].personality | enum |
| ||
lines[].voice | string | null | The Chat voice the line is to be spoken in. |
| |
voice | object |
| ||
voice.mode | enum | yes | Watch is the quiet mode; narrated is the one where the agent says what it is doing. |
|
voice.personality | enum | yes |
| |
voice.voice | string | null | The Chat voice the agent speaks in. Null is the site default. |
| |
voice.muted | boolean | yes | The kill switch: the owner or a channel moderator. It takes effect on the desk at once. | |
voice.own | boolean | The agent speaks in the person own cloned voice. Only with the person own consent. | ||
voice.own_consent_at | string | null | When the person consented to their own cloned voice. The owner view only. |
| |
voice.paused | string | null | Why the voice is paused, or null: allowance_spent when the person allowance ran out. | ||
voice.message | string | null | What the owner is told about the pause, for example voice paused: allowance spent. | ||
captions_url | string | null | Where the recording captions live: the WebVTT a VOD player can attach as a text track. The voice itself is mixed into the stream before the recording, so the recording keeps the voice; the captions are the track beside it. |
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: encoding
{
"viewers": 2,
"encode": true,
"curtain": {
"up": false
},
"ends_at": null
}Valid: snapshot-mode
{
"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"
}Valid: with-voice
{
"viewers": 3,
"encode": true,
"curtain": {
"up": false,
"since": null
},
"ends_at": "2026-11-06T18:00:00.000Z",
"captions_url": "https://openvibe.live/api/streams/agent/ai_123456/captions.vtt",
"lines": [
{
"id": 1,
"at": "2026-11-06T17:00:00.000Z",
"text": "The checkout tests are green.",
"kind": "result",
"personality": "calm",
"voice": "gary"
}
],
"voice": {
"mode": "narrated",
"personality": "calm",
"voice": "gary",
"muted": false,
"own": false,
"own_consent_at": null,
"paused": null,
"message": null
}
}Rejected: negative-viewers
{
"viewers": -1,
"encode": false,
"curtain": {
"up": false
},
"ends_at": null
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('live.agent-stream-state@2', value); // { valid, errors: [{ path, message }] }