---
title: "live.agent-stream@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/live.agent-stream"
updated: null
---

# live.agent-stream@1 · OpenVibe.Services

HTML: [live.agent-stream@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/live.agent-stream)

# LiveAgentStream `live.agent-stream@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: live
- Visibility: first-party
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/live/agent-stream.v1.json`](/docs/contracts/live.agent-stream.json)

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.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string | yes | The agent stream's id (ULID, Crockford base32). | - `pattern ^ags_[0-9A-HJKMNP-TV-Z]{26}$` |
| `owner` | string | yes | The person the stream is theirs. | - `pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$` |
| `channel` | string | yes | The owner's Live channel username (the stream's page lives under it). | - `minLength 1`<br>- `maxLength 64` |
| `title` | string | yes |  | - `minLength 1`<br>- `maxLength 200` |
| `task` | `https://openvibe.network/contracts/live/agent-stream.v1.json#/$defs/task` | yes |  |  |
| `visibility` | enum | yes |  | - `one of "private", "unlisted", "public"` |
| `mode` | enum | yes | How the stream is played. S1 accepts watch only. | - `one of "watch", "narrated", "copilot", "chatplays"` |
| `state` | enum | yes |  | - `one of "idle", "live", "ended"` |
| `curtain` | object | yes |  | - `no other fields` |
| `curtain.up` | boolean | yes |  |  |
| `curtain.since` | string \| null |  | When it went up; absent while it is down. | - `format date-time` |
| `viewers` | integer | yes |  | - `minimum 0` |
| `started_at` | string \| null | yes |  | - `format date-time` |
| `ended_at` | string \| null | yes |  | - `format date-time` |
| `worked_seconds` | integer | yes | How long the agent worked (the card's 'worked 42 min'). | - `minimum 0` |
| `last_frame_url` | string \| null | yes | The last frame the desk sent (JPEG or WebP), or null before the first one. | - `format uri` |
| `vod_id` | string \| null | yes | Media's id once the recording is stored. |  |
| `page_url` | string | yes | The owner's page, /@person/agents/<ags\_id> (with ?k= for the owner of an unlisted stream). | - `pattern ^https://openvibe\.live/`<br>- `format uri` |
| `label` | const | yes | Always shown, so a viewer knows whose stream this is. | - `= "AI agent"` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: live-unlisted

~~~~
{
  "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"
}
~~~~

Valid: private-idle

~~~~
{
  "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"
}
~~~~

Rejected: not-an-agent-stream-id

~~~~
{
  "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"
}
~~~~

Rejected: other-label

~~~~
{
  "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"
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('live.agent-stream@1', value);   // { valid, errors: [{ path, message }] }
~~~~
