> 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`   | `bool`                | `true` 当 WebRTC 视频轨道正在主动发送时。       |
| `FrameSource`    | `IVisionFrameSource`  | 当前正在使用的帧源。 `null` 直到运行时注册完成。       |
| `PublishPolicy`  | `VisionPublishPolicy` | 当前的发布策略。                           |
| `VideoTrackName` | `string`              | 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`

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

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

### `IVisionFrameSourceStatusProvider`

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

| 成员               | Kind                       | 说明                                                    |
| ---------------- | -------------------------- | ----------------------------------------------------- |
| `State`          | `VisionSourceState` 属性     | 当前生命周期状态。                                             |
| `ErrorKind`      | `VisionSourceErrorKind` 属性 | 当以下情况时的结构化错误类别： `State == Failed`.                    |
| `StatusMessage`  | `string` 属性                | 人类可读的状态详情。                                            |
| `HasUsableFrame` | `bool` 属性                  | `true` 当该源至少已生成一个有效帧时。                                |
| `StatusChanged`  | `事件 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] 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` 引用

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

### `ConvaiRoomManager` vision 方法

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

{% hint style="info" %}
自定义 `IConvaiRoomConnectionService` 实现必须实现下面全部三个方法。若 `false` 该实现不支持 vision，则任一方法都返回
{% 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` 会被更改。用户文本和语音始终响应，且无法更改。

| 值               | 连线模态             | 说明                     |
| --------------- | ---------------- | ---------------------- |
| `视觉`            | `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`

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

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

### `VisionFrameCaptured`

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

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

### `VisionCaptureStopped`

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

| 属性                    | 类型                        | 说明                                                                           |
| --------------------- | ------------------------- | ---------------------------------------------------------------------------- |
| `TotalFramesCaptured` | `long`                    | 会话期间捕获的总帧数。                                                                  |
| `时间戳`                 | `DateTime`                | UTC 停止时间。                                                                    |
| `原因`                  | `VisionCaptureStopReason` | 捕获停止的原因（`UserRequested`, `SessionEnded`, `CameraLost`, `Error`, `组件已禁用`).    |
| `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` 非空。                                                     |

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

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

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

| 属性              | 类型         | 说明                                                  |
| --------------- | ---------- | --------------------------------------------------- |
| `TrackSid`      | `string`   | LiveKit 轨道会话 ID。                                    |
| `TrackName`     | `string`   | 由以下项设置的轨道名称 `VideoTrackName` （默认： `"unity-scene"`). |
| `时间戳`           | `DateTime` | UTC 发布时间。                                           |
| `RoomSessionId` | `string`   | 房间会话 ID。                                            |
| `IsVisionTrack` | `bool`     | `true` 当 `TrackName == "vision"` （不区分大小写）。          |

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

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

| 属性                  | 类型                          | 说明                                                                                     |
| ------------------- | --------------------------- | -------------------------------------------------------------------------------------- |
| `TrackSid`          | `string`                    | LiveKit 轨道会话 ID。                                                                       |
| `TrackName`         | `string`                    | 轨道名称。                                                                                  |
| `时间戳`               | `DateTime`                  | UTC 取消发布时间。                                                                            |
| `原因`                | `VideoTrackUnpublishReason` | 轨道为何被取消发布（`UserRequested`, `SessionEnded`, `SourceLost`, `Error`, `组件已禁用`).            |
| `RoomSessionId`     | `string`                    | 房间会话 ID。                                                                               |
| `IsVisionTrack`     | `bool`                      | `true` 当 `TrackName == "vision"` （与以下内容有同样的注意事项） `VideoTrackPublished.IsVisionTrack`). |
| `IsNormalUnpublish` | `bool`                      | `true` 当 `原因` 是 `UserRequested` 或 `SessionEnded`.                                      |

### `VisionContextStatusReceived`

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

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

### `VisionContextTriggerReceived`

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

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

### `RespondModeUpdateResultReceived`

后端对以下内容的确认 `respond-mode-update` 请求，通过以下方式发送 `UpdateRespondMode`，回显已应用的 lane 和模式，或者在 lane 无法更改时回显拒绝结果。

| 属性          | 类型         | 说明                                                     |
| ----------- | ---------- | ------------------------------------------------------ |
| `状态`        | `string`   | 响应状态： `success` 在应用时， `error` 在拒绝时。                    |
| `Message`   | `string`   | 可选的人类可读消息（例如用户输入 lane 的拒绝原因）。                          |
| `UpdateId`  | `string`   | 请求幂等键的回显，当后端返回该值时。                                     |
| `模态`        | `string`   | 更新所针对的 lane，作为后端模态字符串（例如。 `vision`, `context_update`). |
| `模式`        | `string`   | 该 lane 当前生效的响应模式（`silent`/`auto`/`must_respond`).      |
| `RawExtras` | `JObject`  | 完整的 extras 载荷，包括后端的完整 `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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
