> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/scripting-api.md).

# 视觉脚本 API

Vision 脚本的核心是 `ConvaiVisionPublisher` 用于发布控制， `ConvaiRoomManager` 用于按需查询 Vision 状态和触发器，以及用于捕获状态的帧源状态接口。域事件可让你在不轮询的情况下响应生命周期变化和后端确认 `IsPublishing` 每一帧。

### `ConvaiVisionPublisher`

`ConvaiVisionPublisher` 是一个 `MonoBehaviour` 用于管理 WebRTC 视频轨道。通过以下方式获取引用： `GetComponent` 或序列化字段。

#### 属性

| 属性               | 类型                    | 描述                                 |
| ---------------- | --------------------- | ---------------------------------- |
| `IsPublishing`   | `bool`                | `true` 当 WebRTC 视频轨道正在主动发送时。       |
| `FrameSource`    | `IVisionFrameSource`  | 当前使用的帧源。 `null` 直到运行时注册完成。         |
| `PublishPolicy`  | `VisionPublishPolicy` | 当前的发布策略。                           |
| `VideoTrackName` | `string`              | WebRTC 轨道的名称（默认： `"unity-scene"`). |

#### 方法

| 方法                                             | 描述                                                   |
| ---------------------------------------------- | ---------------------------------------------------- |
| `SetPublishPolicy(VisionPublishPolicy policy)` | 更改客户端传输预算。在下一帧已发布的内容中生效。                             |
| `EnablePublishing(bool enabled)`               | 在不更改所选策略的情况下开始或停止发布。仅在策略为 `Manual`时有意义；对于自动发布策略会被忽略。 |

#### 用法

```csharp
using Convai.Modules.Vision;
using Convai.Runtime.Vision.Publishing;
using UnityEngine;

public class VisionController : MonoBehaviour
{
    [SerializeField] private ConvaiVisionPublisher _publisher;

    void Start()
    {
        // 切换到此场景的高响应模式
        _publisher.SetPublishPolicy(VisionPublishPolicy.HighResponsiveness);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.V))
        {
            bool isPublishing = _publisher.IsPublishing;
            Debug.Log($"轨道 '{_publisher.VideoTrackName}' 正在发布：{isPublishing}");
        }
    }
}
```

### `IVisionFrameSource`

由所有内置帧源以及任何自定义源实现。

| 成员                     | 类型                           | 描述                                         |
| ---------------------- | ---------------------------- | ------------------------------------------ |
| `IsCapturing`          | `bool` 属性                    | `true` 当源正在主动生成帧时。                         |
| `FrameCount`           | `long` 属性                    | 自捕获开始以来生成的总帧数。                             |
| `FrameDimensions`      | `(int Width, int Height)` 属性 | 输出分辨率。返回 `(0, 0)` 在初始化之前。                  |
| `TargetFrameRate`      | `float` 属性                   | 配置的每秒帧数。                                   |
| `SourceId`             | `string` 属性                  | 用于多源场景的标识字符串。                              |
| `CurrentRenderTexture` | `RenderTexture` 属性           | Y 轴翻转 `RenderTexture` 包含最新帧。 `null` 在未捕获时。 |
| `IsFrameReady`         | `bool` 属性                    | `true` 在第一个可用帧就绪之后。                        |
| `FrameReady`           | `event Action`               | 每次有新帧可用时在 Unity 主线程上触发。                    |
| `StartCapture()`       | 方法                           | 开始帧捕获。                                     |
| `StopCapture()`        | 方法                           | 停止帧捕获并释放资源。                                |

### `IVisionFrameSourceStatusProvider`

内置源实现的可选配套接口。提供更丰富的状态和错误信息。

| 成员               | 类型                         | 描述                                                 |
| ---------------- | -------------------------- | -------------------------------------------------- |
| `State`          | `VisionSourceState` 属性     | 当前生命周期状态。                                          |
| `ErrorKind`      | `VisionSourceErrorKind` 属性 | 当 `State == Failed`.                               |
| `StatusMessage`  | `string` 属性                | 人类可读的状态详情。                                         |
| `HasUsableFrame` | `bool` 属性                  | `true` 当该源至少已生成一个有效帧时。                             |
| `StatusChanged`  | `event Action`             | 每当 `State`, `ErrorKind`，或 `StatusMessage` 发生变化时触发。 |

### 监视状态变化

```csharp
using Convai.Runtime.Vision.Sources;
using UnityEngine;

public class FrameSourceMonitor : MonoBehaviour
{
    [SerializeField] private MonoBehaviour _frameSourceComponent;

    private IVisionFrameSourceStatusProvider _statusProvider;

    void Start()
    {
        _statusProvider = _frameSourceComponent as IVisionFrameSourceStatusProvider;
        if (_statusProvider != null)
            _statusProvider.StatusChanged += OnStatusChanged;
    }

    void OnDestroy()
    {
        if (_statusProvider != null)
            _statusProvider.StatusChanged -= OnStatusChanged;
    }

    private void OnStatusChanged()
    {
        Debug.Log($"[Vision] 状态：{_statusProvider.State}  错误：{_statusProvider.ErrorKind}  {_statusProvider.StatusMessage}");

        if (_statusProvider.State == VisionSourceState.Failed)
            HandleCaptureFailure(_statusProvider.ErrorKind);
    }

    private void HandleCaptureFailure(VisionSourceErrorKind errorKind)
    {
        switch (errorKind)
        {
            case VisionSourceErrorKind.PermissionDenied:
                // 显示 UI，提示用户授予摄像头权限
                break;
            case VisionSourceErrorKind.DeviceUnavailable:
                // 提供切换到其他帧源的选项
                break;
        }
    }
}
```

### `VisionSourceState` 参考

| State                | 含义                                          |
| -------------------- | ------------------------------------------- |
| `空闲`                 | 尚未开始捕获。                                     |
| `AwaitingPermission` | 等待用户授予摄像头权限（Android / iOS）。                 |
| `Starting`           | 捕获正在初始化——设备正在打开， `RenderTexture`s 正在创建。     |
| `Ready`              | 捕获正在运行并且帧正在生成。                              |
| `Degraded`           | 捕获正在运行，但帧健康检查检测到问题（例如连续空白帧）。                |
| `Stopped`            | 捕获已正常停止。                                    |
| `Failed`             | 捕获失败且无法继续。检查 `ErrorKind` 和 `StatusMessage`. |

### `ConvaiRoomManager` vision 方法

`ConvaiRoomManager` 实现 `IConvaiRoomConnectionService` 并公开三个运行时方法，这些方法在 SDK 4.4.0 中新增，用于在会话中途查询和驱动动态 Vision 上下文，而无需重新连接。可通过序列化的 `ConvaiRoomManager` 字段、自定义 `IConvaiRoomConnectionService` 实现，或 `ConvaiManager.ActiveManager.TryGetRoomConnectionService(out IConvaiRoomConnectionService service)` 在没有场景引用可用时。

{% hint style="warning" %}
**SDK 4.4.0 中的破坏性变更。** `IConvaiRoomConnectionService` 新增了三个成员： `RequestVisionStatus(string updateId = null)`, `TriggerVision(ConvaiVisionTriggerRequest request)`，以及 `UpdateRespondMode(ConvaiRespondModeLane lane, ConvaiRespondMode mode, string updateId = null)`. 仅通过 `ConvaiRoomManager` 消费该接口的代码不受影响。任何对 `IConvaiRoomConnectionService` 的自定义实现必须添加全部三个方法——如果该实现不支持 vision，则每个方法都应返回 `false` 。
{% endhint %}

| 方法                                                                                              | 返回     | 描述                                                                                                                      |
| ----------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------- |
| `RequestVisionStatus(string updateId = null)`                                                   | `bool` | 请求后端为当前会话提供动态 Vision 缓冲区/状态诊断。后端会以 [`VisionContextStatusReceived`](#visioncontextstatusreceived).                       |
| `TriggerVision(ConvaiVisionTriggerRequest request)`                                             | `bool` | 请求后端为当前会话提供动态 Vision 附加/响应行为——要求角色查看缓存帧，并根据请求作出响应。后端会以 [`VisionContextTriggerReceived`](#visioncontexttriggerreceived). |
| `UpdateRespondMode(ConvaiRespondModeLane lane, ConvaiRespondMode mode, string updateId = null)` | `bool` | 在不重新连接的情况下，为本次会话的剩余时间更改某个输入通道的响应模式。后端会以 [`RespondModeUpdateResultReceived`](#respondmodeupdateresultreceived).          |

每个方法都会在 `false` 没有会话传输可用时返回（例如在房间连接之前）。

```csharp
using Convai.Runtime;
using Convai.Runtime.Adapters.Networking;
using Convai.Runtime.Vision.Context;
using UnityEngine;

public class VisionRuntimeQueries : MonoBehaviour
{
    [SerializeField] private ConvaiRoomManager _roomManager;

    public void QueryVisionStatus()
    {
        // 答案以 VisionContextStatusReceived 的形式到达。
        _roomManager.RequestVisionStatus();
    }

    public void TriggerVisionLook()
    {
        var request = new ConvaiVisionTriggerRequest
        {
            Text = "桌子上有什么变化？",
            RespondMode = ConvaiRespondMode.MustRespond
        };
        request.SetFrameWindow(-5, -1); // 最近缓存的五帧

        // 答案以 VisionContextTriggerReceived 的形式到达。
        _roomManager.TriggerVision(request);
    }

    public void SwitchVisionToAuto()
    {
        // 由 RespondModeUpdateResultReceived 确认。
        _roomManager.UpdateRespondMode(ConvaiRespondModeLane.Vision, ConvaiRespondMode.Auto);
    }
}
```

### `ConvaiVisionTriggerRequest`

`Convai.Runtime.Vision.Context` — 密封类

通过以下方式发送的显式动态 Vision 触发参数： `TriggerVision`. 触发会请求后端将缓存的 vision 帧附加到一次轮次中，并且根据 `RespondMode`，调用模型。未设置帧选择时，后端会附加其配置的每轮帧数内最新的新鲜帧。

```csharp
new ConvaiVisionTriggerRequest(string updateId = null)
```

| 参数         | 类型       | 默认值    | 描述                                                                                      |
| ---------- | -------- | ------ | --------------------------------------------------------------------------------------- |
| `updateId` | `string` | `null` | 在确认消息的 `update_id`中回显的幂等键。省略时会生成唯一 ID。重复使用相同 ID 会使请求具有幂等性——后端会重放原始确认而不是再次触发，因此重试始终是安全的。 |

#### 属性

| 属性                 | 类型                    | 描述                                                                                       |
| ------------------ | --------------------- | ---------------------------------------------------------------------------------------- |
| `UpdateId`         | `string`              | 此请求的幂等键，由构造函数设置。                                                                         |
| `Text`             | `string`              | 可选的提示词，随帧一起发送，例如 `"桌子上有什么变化？"`. 为空时，后端会使用其通用的“检查这些帧”提示词。                                 |
| `RespondMode`      | `ConvaiRespondMode?`  | 此触发如何影响角色的讲话。 `null` 使用触发通道的连接时默认值（`ConvaiVisionRespondModeSettings.Trigger`).           |
| `FrameWindowStart` | `int?`                | 相对帧窗口的起始位置，通过以下方式设置： `SetFrameWindow`.                                                   |
| `FrameWindowEnd`   | `int?`                | 相对帧窗口的结束位置，通过以下方式设置： `SetFrameWindow`.                                                   |
| `FramePtsIds`      | `IReadOnlyList<long>` | 可选的按展示时间戳（纳秒）进行的绝对帧选择，如确认消息中所报告（`attached_frame_pts`）以及 vision 状态响应中所报告。当两者都设置时，它优先于帧窗口。 |

#### 方法

| 方法                                             | 描述                                                                                                                             |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `SetFrameWindow(int startIndex, int endIndex)` | 选择缓存帧的相对窗口，例如 `SetFrameWindow(-5, -1)` 表示最近的五帧。负值从最新缓存帧开始倒数（`-1` = 最新）；非负值是从最早保留帧开始的零基偏移。后端会将超出范围的索引裁剪到最早保留帧，并在确认消息中报告实际附加的内容。 |
| `ClearFrameWindow()`                           | 清除之前设置的帧窗口，恢复默认的最新帧选择。                                                                                                         |

触发中的帧选择，按优先级顺序：

1. `FramePtsIds` — 按展示时间戳进行绝对固定。不受陈旧窗口限制；若某个时间戳对应的帧已离开缓冲区，则触发会失败，结果为 `frame_id_evicted` 。
2. `SetFrameWindow(startIndex, endIndex)` — 相对窗口，如上所述。
3. 未设置任何内容——后端会附加其配置的每轮帧数内最新的新鲜帧。

### `ConvaiRespondModeLane`

`Convai.Runtime.Vision.Context` — 枚举

标识哪个输入通道的响应模式 `UpdateRespondMode` 会发生变化。用户文本和语音始终响应，且无法更改。

| 值               | Wire 模态          | 描述                    |
| --------------- | ---------------- | --------------------- |
| `视觉`            | `vision`         | 新采样的 vision 帧。        |
| `ContextUpdate` | `context_update` | 动态上下文文本更新。            |
| `Trigger`       | `trigger`        | 不带每请求模式的显式 vision 触发。 |
| `SceneMetadata` | `scene_metadata` | 场景元数据更新。              |

### 域事件

通过运行时订阅域事件 `IEventHub` 以便在不轮询每一帧的情况下响应 Vision 生命周期变化和后端确认 `IsPublishing` 。通过以下方式获取事件中心： `ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)`. 所有 Vision 事件都是值类型（`readonly struct`）——只需分配一次处理程序并保留引用。

```csharp
using Convai.Domain.DomainEvents.Vision;
using Convai.Domain.EventSystem;
using Convai.Runtime.Components;
using UnityEngine;

public class VisionAnalytics : MonoBehaviour
{
    private SubscriptionToken _captureStartedToken;
    private SubscriptionToken _captureStoppedToken;
    private SubscriptionToken _trackPublishedToken;
    private SubscriptionToken _trackUnpublishedToken;
    private SubscriptionToken _visionStatusToken;
    private SubscriptionToken _visionTriggerToken;
    private SubscriptionToken _respondModeToken;

    void Start()
    {
        if (ConvaiManager.ActiveManager == null) return;
        if (!ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)) return;

        _captureStartedToken = hub.Subscribe<VisionCaptureStarted>(OnCaptureStarted, EventDeliveryPolicy.MainThread);
        _captureStoppedToken = hub.Subscribe<VisionCaptureStopped>(OnCaptureStopped, EventDeliveryPolicy.MainThread);
        _trackPublishedToken = hub.Subscribe<VideoTrackPublished>(OnTrackPublished, EventDeliveryPolicy.MainThread);
        _trackUnpublishedToken = hub.Subscribe<VideoTrackUnpublished>(OnTrackUnpublished, EventDeliveryPolicy.MainThread);
        _visionStatusToken = hub.Subscribe<VisionContextStatusReceived>(OnVisionStatus, EventDeliveryPolicy.MainThread);
        _visionTriggerToken = hub.Subscribe<VisionContextTriggerReceived>(OnVisionTrigger, EventDeliveryPolicy.MainThread);
        _respondModeToken = hub.Subscribe<RespondModeUpdateResultReceived>(OnRespondModeUpdate, EventDeliveryPolicy.MainThread);
    }

    void OnDestroy()
    {
        if (ConvaiManager.ActiveManager == null) return;
        if (!ConvaiManager.ActiveManager.TryGetEventHub(out IEventHub hub)) return;

        hub.Unsubscribe(_captureStartedToken);
        hub.Unsubscribe(_captureStoppedToken);
        hub.Unsubscribe(_trackPublishedToken);
        hub.Unsubscribe(_trackUnpublishedToken);
        hub.Unsubscribe(_visionStatusToken);
        hub.Unsubscribe(_visionTriggerToken);
        hub.Unsubscribe(_respondModeToken);
    }

    private void OnCaptureStarted(VisionCaptureStarted e)
        => Debug.Log($"[Vision] 捕获已开始：{e.Width}x{e.Height} @ {e.FramesPerSecond} fps（源：{e.SourceId}）");

    private void OnCaptureStopped(VisionCaptureStopped e)
    {
        Debug.Log($"[Vision] 捕获在 {e.TotalFramesCaptured} 帧后停止。原因：{e.Reason}");
        if (e.IsError)
            Debug.LogError($"[Vision] 错误：{e.ErrorMessage}（代码：{e.ErrorCode}）");
    }

    private void OnTrackPublished(VideoTrackPublished e)
        => Debug.Log($"[Vision] 轨道 '{e.TrackName}' 已发布。SID：{e.TrackSid}");

    private void OnTrackUnpublished(VideoTrackUnpublished e)
        => Debug.Log($"[Vision] 轨道 '{e.TrackName}' 已取消发布。原因：{e.Reason}");

    private void OnVisionStatus(VisionContextStatusReceived e)
        => Debug.Log($"[Vision] 状态：{e.Outcome}（源：{e.ActiveSourceLabel}，上一帧时间：{e.LastFrameAgeMs} 毫秒）");

    private void OnVisionTrigger(VisionContextTriggerReceived e)
        => Debug.Log($"[Vision] 触发：{e.Outcome}，附加了 {e.FramesAttached} 帧，响应模式 {e.ActualRespondMode}");

    private void OnRespondModeUpdate(RespondModeUpdateResultReceived e)
        => Debug.Log($"[Vision] '{e.Modality}' 的响应模式现在是 '{e.Mode}'（状态：{e.Status}）");
}
```

### `VisionCaptureStarted`

当帧源开始生成帧时触发。

| 属性                | 类型         | 描述                                      |
| ----------------- | ---------- | --------------------------------------- |
| `Width`           | `int`      | 以像素为单位的捕获宽度。                            |
| `Height`          | `int`      | 以像素为单位的捕获高度。                            |
| `FramesPerSecond` | `float`    | 配置的帧率。                                  |
| `时间戳`             | `DateTime` | 捕获开始的 UTC 时间。                           |
| `SourceId`        | `string`   | 源标识符（来自 `IVisionFrameSource.SourceId`). |
| `AspectRatio`     | `float`    | `Width / Height`.                       |
| `TotalPixels`     | `int`      | `Width * Height`.                       |

### `VisionFrameCaptured`

每次捕获到一帧时触发。此事件会在每个被捕获的帧上触发——在 60 秒会话中以 15 fps 运行时，这相当于 900 个事件。请使用 `EventDeliveryPolicy.Immediate` 并保持处理程序轻量；对于分析，采样每第 N 帧，而不是订阅每个事件。

| 属性           | 类型         | 描述            |
| ------------ | ---------- | ------------- |
| `Width`      | `int`      | 帧宽度（像素）。      |
| `Height`     | `int`      | 帧高度（像素）。      |
| `FrameIndex` | `long`     | 从 0 开始的捕获帧索引。 |
| `SizeBytes`  | `long`     | 帧数据大小（字节）。    |
| `时间戳`        | `DateTime` | 捕获该帧的 UTC 时间。 |
| `SourceId`   | `string`   | 源标识符。         |

### `VisionCaptureStopped`

当帧源停止生成帧时触发。

| 属性                    | 类型                        | 描述                                                                                 |
| --------------------- | ------------------------- | ---------------------------------------------------------------------------------- |
| `TotalFramesCaptured` | `long`                    | 会话期间捕获的总帧数。                                                                        |
| `时间戳`                 | `DateTime`                | UTC 停止时间。                                                                          |
| `原因`                  | `VisionCaptureStopReason` | 捕获停止的原因（`UserRequested`, `SessionEnded`, `CameraLost`, `错误`, `ComponentDisabled`). |
| `SourceId`            | `string`                  | 源标识符。                                                                              |
| `错误消息`                | `string`                  | 人类可读的错误详情。仅在 `Reason == Error`.                                                    |
| `ErrorCode`           | `string`                  | 来自 `SessionErrorCodes` （Vision\* 常量）。仅在 `Reason == Error`.                         |
| `IsError`             | `bool`                    | `true` 时自动连接， `Reason == Error`.                                                   |
| `IsNormalStop`        | `bool`                    | `true` 时自动连接， `原因` 为 `UserRequested` 或 `SessionEnded`.                             |
| `HasErrorCode`        | `bool`                    | `true` 时自动连接， `ErrorCode` 非空时存在。                                                   |

### `VideoTrackPublished`

当 WebRTC 视频轨道成功打开时触发。

{% hint style="warning" %}
`IsVisionTrack` 检查轨道名称 `"vision"`，而不是 `"unity-scene"`。使用默认轨道名称时， `IsVisionTrack` 返回 `false`。在选择索引之前，使用 `TrackName` 可直接用于识别该轨道，或者将轨道重命名为 `"vision"` ，如果你的集成依赖于 `IsVisionTrack`.
{% endhint %}

| 属性              | 类型         | 描述                                              |
| --------------- | ---------- | ----------------------------------------------- |
| `TrackSid`      | `string`   | LiveKit 轨道会话 ID。                                |
| `TrackName`     | `string`   | 轨道名称，由 `VideoTrackName` （默认： `"unity-scene"`).  |
| `时间戳`           | `DateTime` | UTC 发布时间。                                       |
| `RoomSessionId` | `string`   | 房间会话 ID。                                        |
| `IsVisionTrack` | `bool`     | `true` 时自动连接， `TrackName == "vision"` （不区分大小写）。 |

### `VideoTrackUnpublished`

当 WebRTC 视频轨道被移除时触发。

| 属性                  | 类型                          | 描述                                                                                   |
| ------------------- | --------------------------- | ------------------------------------------------------------------------------------ |
| `TrackSid`          | `string`                    | LiveKit 轨道会话 ID。                                                                     |
| `TrackName`         | `string`                    | 轨道名称。                                                                                |
| `时间戳`               | `DateTime`                  | UTC 取消发布时间。                                                                          |
| `原因`                | `VideoTrackUnpublishReason` | 轨道取消发布的原因（`UserRequested`, `SessionEnded`, `SourceLost`, `错误`, `ComponentDisabled`). |
| `RoomSessionId`     | `string`                    | 房间会话 ID。                                                                             |
| `IsVisionTrack`     | `bool`                      | `true` 时自动连接， `TrackName == "vision"` （与 `VideoTrackPublished.IsVisionTrack`).       |
| `IsNormalUnpublish` | `bool`                      | `true` 时自动连接， `原因` 为 `UserRequested` 或 `SessionEnded`.                               |

### `VisionContextStatusReceived`

后端对一个 `vision-status` 查询的确认，通过 `RequestVisionStatus`发送，描述会话动态视觉帧缓冲区的状态。

| 属性                  | 类型         | 描述                                                                                   |
| ------------------- | ---------- | ------------------------------------------------------------------------------------ |
| `Status`            | `string`   | 响应状态： `success`, `error`, `processing`，或 `pending`.                                  |
| `消息`                | `string`   | 响应附带的可选人类可读消息。                                                                       |
| `UpdateId`          | `string`   | 请求幂等键的回显。                                                                            |
| `结果`                | `string`   | 缓冲区结果： `frames_available`, `buffer_empty`, `no_active_video`，或 `vision_not_enabled`. |
| `ActiveSource`      | `string`   | 本次会话中后端选择的视频源的参与者 ID（如果有）。                                                           |
| `ActiveSourceLabel` | `string`   | 所选视频发布者的源标签（例如 webcam、canvas、screen）。                                                |
| `LastFrameAgeMs`    | `int`      | 最新缓冲帧的时长，单位毫秒； `0` 当未知或未缓冲任何帧时。                                                      |
| `RawExtras`         | `JObject`  | 完整的额外载荷，包括 `vision_buffer` diagnostics 对象（保留的帧、PTS 窗口、丢弃计数器），用于没有类型化访问器的字段。          |
| `时间戳`               | `DateTime` | 此事件在客户端创建的 UTC 时间。                                                                   |

### `VisionContextTriggerReceived`

后端对一个 `vision-trigger` 请求，经由 `TriggerVision`，报告触发器如何被解析（respond 模式、降级）以及哪些帧被附加到模型轮次。

| 属性                     | 类型                    | 描述                                                                                                                                                      |
| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Status`               | `string`              | 响应状态： `success`, `error`, `processing`，或 `pending`.                                                                                                     |
| `消息`                   | `string`              | 响应附带的可选人类可读消息。                                                                                                                                          |
| `UpdateId`             | `string`              | 请求幂等键的回显。                                                                                                                                               |
| `结果`                   | `string`              | 触发结果，例如 `frames_available`, `buffer_empty`, `vision_not_enabled`, `invalid_respond_mode`, `invalid_frame_indices`, `frame_id_evicted`，或 `rate_limited`. |
| `RequestedRespondMode` | `string`              | 请求所要求的 respond 模式（`silent`/`auto`/`must_respond`).                                                                                                      |
| `ActualRespondMode`    | `string`              | 后端在基于状态降级后实际应用的 respond 模式。                                                                                                                             |
| `RequestedRunLlm`      | `string`              | 线上请求的 LLM 策略（`true`/`auto`/`false`).                                                                                                                    |
| `ActualRunLlm`         | `string`              | 降级后实际应用的 LLM 策略。                                                                                                                                        |
| `LlmTriggered`         | `bool`                | `true` 当触发器导致一次 LLM 调用时。                                                                                                                                |
| `Downgraded`           | `bool`                | `true` 当后端降低所请求的 respond 模式时（例如机器人忙、用户正在说话）。                                                                                                            |
| `DowngradeReason`      | `string`              | 请求被降级的原因，例如 `bot_busy` 或 `user_speaking`；否则为空。                                                                                                          |
| `FramesAttached`       | `int`                 | 附加到该轮次的图像帧数量。                                                                                                                                           |
| `AttachOutcome`        | `string`              | 附加结果： `attached`, `deduped_stub`, `stale_skipped`，或 `无`.                                                                                                |
| `ImageTokensEstimate`  | `int`                 | 后端估算所附加帧消耗的图像 token 数（仅用于归因，不用于计费）。                                                                                                                     |
| `AttachedFramePts`     | `IReadOnlyList<long>` | 模型看到的确切帧的展示时间戳（纳秒）。                                                                                                                                     |
| `RawExtras`            | `JObject`             | 完整的额外载荷（包括 `vision_buffer` diagnostics），用于没有类型化访问器的字段。                                                                                                  |
| `时间戳`                  | `DateTime`            | 此事件在客户端创建的 UTC 时间。                                                                                                                                      |

### `RespondModeUpdateResultReceived`

后端对一个 `respond-mode-update` 请求，经由 `UpdateRespondMode`，回显所应用的 lane 和模式，或者在无法更改 lane 时返回拒绝结果。

| 属性          | 类型         | 描述                                                       |
| ----------- | ---------- | -------------------------------------------------------- |
| `Status`    | `string`   | 响应状态： `success` 应用时， `error` 被拒绝时。                       |
| `消息`        | `string`   | 可选的人类可读消息（例如用户输入 lane 的拒绝原因）。                            |
| `UpdateId`  | `string`   | 请求幂等键的回显，如果后端返回了的话。                                      |
| `模态`        | `string`   | 更新所针对的 lane，作为后端模态字符串（例如 `vision`, `context_update`).    |
| `模式`        | `string`   | 该 lane 现在生效的 respond 模式（`silent`/`auto`/`must_respond`). |
| `RawExtras` | `JObject`  | 完整的额外载荷，包括后端完整的 `respond_modes` lane 快照。                 |
| `时间戳`       | `DateTime` | 此事件在客户端创建的 UTC 时间。                                       |

### 下一步

{% content-ref url="/pages/cb7758289bc48a93210bce51933fd819fd05e245" %}
[自定义帧源](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/custom-frame-sources.md)
{% endcontent-ref %}

{% content-ref url="/pages/86612bc613c5a299a468b71b3fb8a40e625ee1fe" %}
[排查视觉问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/troubleshooting-and-diagnostics.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/vision/scripting-api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
