> 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).

# Vision 脚本 API

Convai Unity SDK Vision 脚本 API 参考，包括发布控制、运行时状态查询、按需触发以及 respond-mode 事件。

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

### `ConvaiVisionPublisher`

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

#### 属性

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

#### 方法

| 方法                                             | 说明                                                                                                |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `SetPublishPolicy(VisionPublishPolicy policy)` | 更改客户端传输预算。将在下一帧发布时生效。                                                                             |
| `EnablePublishing(bool enabled)`               | 在不更改所选策略的情况下开始或停止发布。该设置对所有策略都生效，而不仅仅是 `手动`。调用后，它还会在本次会话剩余时间内覆盖该策略自身的默认开/关设置，因此后续的策略更改将不再决定是否进行发布。 |

#### 用法

```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($"Track '{_publisher.VideoTrackName}' publishing: {isPublishing}");
        }
    }
}
```

### `IVisionFrameSource`

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

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

### `IVisionFrameSourceStatusProvider`

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

| 成员               | 类型                         | 说明                                |
| ---------------- | -------------------------- | --------------------------------- |
| `状态`             | `VisionSourceState` 属性     | 当前生命周期状态。                         |
| `错误类型`           | `VisionSourceErrorKind` 属性 | 结构化错误类别，当 `State == Failed`.      |
| `状态消息`           | `字符串` 属性                   | 人类可读的状态详情。                        |
| `HasUsableFrame` | `布尔值` 属性                   | `是` 当该源已生成至少一个有效帧时。               |
| `StatusChanged`  | `event Action`             | 每当 `状态`, `错误类型`，或 `状态消息` 发生变化时触发。 |

### 监控状态变化

```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] State: {_statusProvider.State}  Error: {_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` 引用

| 状态       | 含义                                      |
| -------- | --------------------------------------- |
| `空闲`     | 捕获尚未开始。                                 |
| `等待权限`   | 等待用户授予相机权限（Android / iOS）。              |
| `启动中`    | 捕获正在初始化——设备正在打开， `RenderTexture`s 正在创建。 |
| `就绪`     | 捕获正在运行，帧正在生成。                           |
| `降级`     | 捕获正在运行，但帧健康检查检测到问题（例如连续空白帧）。            |
| `已停止`    | 捕获已正常停止。                                |
| `Failed` | 捕获失败且无法继续。请检查 `错误类型` 和 `状态消息`.          |

### `ConvaiRoomManager` vision 方法

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

{% hint style="info" %}
自定义 `IConvaiRoomConnectionService` 实现必须实现下面的三个方法。返回 `否` 当该实现不支持 vision 时，可在任一方法中返回。
{% endhint %}

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

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

```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); // 最近缓冲的 5 帧

        // 响应会以 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` | `字符串` | `null` | 幂等键，会在确认中的 `update_id`中回传。省略时将生成唯一 ID。重复使用同一 ID 会使请求具有幂等性——后端会重放原始确认而不是再次触发，因此重试始终安全。 |

#### 属性

| 属性                 | 类型                    | 说明                                                                                  |
| ------------------ | --------------------- | ----------------------------------------------------------------------------------- |
| `UpdateId`         | `字符串`                 | 由构造函数设置的此请求幂等键。                                                                     |
| `文本`               | `字符串`                 | 附带帧的可选提示，例如 `"桌子上有什么变化？"`。为空时，后端将使用其通用的“检查帧”提示。                                     |
| `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)` 表示最近的 5 帧。负值从最新的缓冲帧向前计数（`-1` = 最新）；非负值是从最早保留帧开始的零基偏移。后端会将越界索引钳制到最早保留帧，并在确认中报告实际附加了哪些帧。 |
| `ClearFrameWindow()`                           | 清除先前设置的帧窗口，恢复默认的最新帧选择。                                                                                                        |

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

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

### `ConvaiRespondModeLane`

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

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

| 值               | 连接模态             | 说明                    |
| --------------- | ---------------- | --------------------- |
| `视觉`            | `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] Capture started: {e.Width}x{e.Height} @ {e.FramesPerSecond} fps (source: {e.SourceId})");

    private void OnCaptureStopped(VisionCaptureStopped e)
    {
        Debug.Log($"[Vision] Capture stopped after {e.TotalFramesCaptured} frames. Reason: {e.Reason}");
        if (e.IsError)
            Debug.LogError($"[Vision] Error: {e.ErrorMessage} (code: {e.ErrorCode})");
    }

    private void OnTrackPublished(VideoTrackPublished e)
        => Debug.Log($"[Vision] Track '{e.TrackName}' published. SID: {e.TrackSid}");

    private void OnTrackUnpublished(VideoTrackUnpublished e)
        => Debug.Log($"[Vision] Track '{e.TrackName}' unpublished. Reason: {e.Reason}");

    private void OnVisionStatus(VisionContextStatusReceived e)
        => Debug.Log($"[Vision] Status: {e.Outcome} (source: {e.ActiveSourceLabel}, last frame age: {e.LastFrameAgeMs} ms)");

    private void OnVisionTrigger(VisionContextTriggerReceived e)
        => Debug.Log($"[Vision] Trigger: {e.Outcome}, attached {e.FramesAttached} frame(s), respond mode {e.ActualRespondMode}");

    private void OnRespondModeUpdate(RespondModeUpdateResultReceived e)
        => Debug.Log($"[Vision] Respond mode for '{e.Modality}' is now '{e.Mode}' (status: {e.Status})");
}
```

### `VisionCaptureStarted`

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

| 属性                | 类型         | 说明                                      |
| ----------------- | ---------- | --------------------------------------- |
| `Width`           | `整数`       | 捕获宽度（像素）。                               |
| `Height`          | `整数`       | 捕获高度（像素）。                               |
| `FramesPerSecond` | `float`    | 配置的帧率。                                  |
| `时间戳`             | `DateTime` | 捕获开始的 UTC 时间。                           |
| `SourceId`        | `字符串`      | 源标识符（来自 `IVisionFrameSource.SourceId`). |
| `AspectRatio`     | `float`    | `宽度 / 高度`.                              |
| `TotalPixels`     | `整数`       | `宽度 * 高度`.                              |

### `VisionFrameCaptured`

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

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

### `VisionCaptureStopped`

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

| 属性          | 类型         | 说明                                                     |
| ----------- | ---------- | ------------------------------------------------------ |
| `总捕获帧数`     | `long`     | 会话期间捕获的总帧数。                                            |
| `时间戳`       | `DateTime` | UTC 停止时间。                                              |
| `原因`        | `视觉捕获停止原因` | 捕获停止原因（`用户请求`, `会话结束`, `摄像头丢失`, `错误`, `组件已禁用`).        |
| `SourceId`  | `字符串`      | 源标识符。                                                  |
| `错误消息`      | `字符串`      | 人类可读的错误详情。仅在 `原因 == Error`.                            |
| `ErrorCode` | `字符串`      | 来自 `SessionErrorCodes` （Vision\* 常量）。仅在 `原因 == Error`. |
| `IsError`   | `布尔值`      | `是` 当 `原因 == Error`.                                   |
| `是否正常停止`    | `布尔值`      | `是` 当 `原因` 是 `用户请求` 或 `会话结束`.                          |
| `是否有错误代码`   | `布尔值`      | `是` 当 `ErrorCode` 非空时。                                 |

### `视频轨道已发布`

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

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

| 属性              | 类型         | 说明                                                  |
| --------------- | ---------- | --------------------------------------------------- |
| `TrackSid`      | `字符串`      | LiveKit 轨道会话 ID。                                    |
| `TrackName`     | `字符串`      | 轨道名称由以下项设置： `VideoTrackName` （默认： `"unity-scene"`). |
| `时间戳`           | `DateTime` | UTC 发布时间。                                           |
| `房间会话 ID`       | `字符串`      | 房间会话 ID。                                            |
| `是否为 Vision 轨道` | `布尔值`      | `是` 当 `TrackName == "vision"` （不区分大小写）。             |

### `视频轨道已取消发布`

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

| 属性              | 类型           | 说明                                                                         |
| --------------- | ------------ | -------------------------------------------------------------------------- |
| `TrackSid`      | `字符串`        | LiveKit 轨道会话 ID。                                                           |
| `TrackName`     | `字符串`        | 轨道名称。                                                                      |
| `时间戳`           | `DateTime`   | UTC 取消发布时间。                                                                |
| `原因`            | `视频轨道取消发布原因` | 轨道为何被取消发布（`用户请求`, `会话结束`, `源丢失`, `错误`, `组件已禁用`).                           |
| `房间会话 ID`       | `字符串`        | 房间会话 ID。                                                                   |
| `是否为 Vision 轨道` | `布尔值`        | `是` 当 `TrackName == "vision"` （注意事项同 `VideoTrackPublished.IsVisionTrack`). |
| `是否正常取消发布`      | `布尔值`        | `是` 当 `原因` 是 `用户请求` 或 `会话结束`.                                              |

### `VisionContextStatusReceived`

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

| 属性         | 类型         | 说明                                                                     |
| ---------- | ---------- | ---------------------------------------------------------------------- |
| `状态`       | `字符串`      | 响应状态： `success`, `错误`, `处理中`，或 `待处理`.                                  |
| `消息`       | `字符串`      | 附带响应的可选人类可读消息。                                                         |
| `UpdateId` | `字符串`      | 请求幂等键的回显。                                                              |
| `结果`       | `字符串`      | 缓冲结果： `有可用帧`, `缓冲区为空`, `无活动视频`，或 `未启用 vision`.                         |
| `活动来源`     | `字符串`      | 后端为该会话选择的视频源参与者 ID（如果有）。                                               |
| `活动来源标签`   | `字符串`      | 所选视频发布者的来源标签（例如 webcam、canvas、screen）。                                 |
| `最新帧年龄毫秒数` | `整数`       | 缓冲区中最新帧的年龄（毫秒）； `0` 当未知或未缓冲任何帧时。                                       |
| `原始附加数据`   | `JObject`  | 完整的 extras 负载，包括 `vision_buffer` 的诊断对象（保留帧、PTS 窗口、丢帧计数），用于没有类型化访问器的字段。 |
| `时间戳`      | `DateTime` | 该事件在客户端创建的 UTC 时间。                                                     |

### `VisionContextTriggerReceived`

后端对以下内容的确认： `vision-trigger` 请求，通过 `TriggerVision`，报告触发如何被处理（响应模式、降级）以及哪些帧被附加到模型轮次。

| 属性             | 类型                    | 说明                                                                                      |
| -------------- | --------------------- | --------------------------------------------------------------------------------------- |
| `状态`           | `字符串`                 | 响应状态： `success`, `错误`, `处理中`，或 `待处理`.                                                   |
| `消息`           | `字符串`                 | 附带响应的可选人类可读消息。                                                                          |
| `UpdateId`     | `字符串`                 | 请求幂等键的回显。                                                                               |
| `结果`           | `字符串`                 | 触发结果，例如 `有可用帧`, `缓冲区为空`, `未启用 vision`, `无效响应模式`, `无效帧索引`, `frame_id_evicted`，或 `受速率限制`. |
| `请求的响应模式`      | `字符串`                 | 请求要求的响应模式（`静默`/`自动`/`必须响应`).                                                            |
| `实际响应模式`       | `字符串`                 | 后端在基于状态的降级后实际应用的响应模式。                                                                   |
| `请求运行 LLM`     | `字符串`                 | 线上请求中的 LLM 策略（`是`/`自动`/`否`).                                                            |
| `实际运行 LLM`     | `字符串`                 | 降级后实际应用的 LLM 策略。                                                                        |
| `触发 LLM`       | `布尔值`                 | `是` 当该触发器导致调用 LLM 时。                                                                    |
| `已降级`          | `布尔值`                 | `是` 当后端降低所请求的响应模式时（例如机器人忙碌、用户在说话）。                                                      |
| `降级原因`         | `字符串`                 | 请求为何被降级，例如 `机器人忙碌` 或 `用户在说话`；否则为空。                                                      |
| `已附加帧数`        | `整数`                  | 附加到该轮次的图像帧数量。                                                                           |
| `附加结果`         | `字符串`                 | 附加结果： `已附加`, `去重占位`, `已跳过过期项`，或 `无`.                                                    |
| `图像 token 估算值` | `整数`                  | 后端估算所附加帧消耗的图像 token 数（仅用于归因，不用于计费）。                                                     |
| `已附加帧 PTS`     | `IReadOnlyList<long>` | 模型实际看到的那些帧的呈现时间戳（纳秒）。                                                                   |
| `原始附加数据`       | `JObject`             | 完整的 extras 负载（包括 `vision_buffer` diagnostics），用于没有类型化访问器的字段。                            |
| `时间戳`          | `DateTime`            | 该事件在客户端创建的 UTC 时间。                                                                      |

### `RespondModeUpdateResultReceived`

后端对以下内容的确认： `respond-mode-update` 请求，通过 `UpdateRespondMode`，回显该通道和已应用的模式，或在通道无法更改时返回拒绝信息。

| 属性         | 类型         | 说明                                                 |
| ---------- | ---------- | -------------------------------------------------- |
| `状态`       | `字符串`      | 响应状态： `success` 在应用时， `错误` 在被拒绝时。                  |
| `消息`       | `字符串`      | 可选的人类可读消息（例如用户输入通道的拒绝原因）。                          |
| `UpdateId` | `字符串`      | 后端返回时，请求幂等键的回显。                                    |
| `模态`       | `字符串`      | 更新所针对的通道，作为后端模态字符串（例如 `vision`, `context_update`). |
| `模式`       | `字符串`      | 该通道当前生效的响应模式（`静默`/`自动`/`必须响应`).                    |
| `原始附加数据`   | `JObject`  | 完整的 extras 负载，包括后端完整的 `respond_modes` 通道快照。        |
| `时间戳`      | `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.
