> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xpertai.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 视图扩展

> 了解 Xpert 插件如何通过视图提供器和视图清单，把声明式视图或远程组件接入工作台等宿主界面。

# 视图扩展

视图扩展（View Extension）是插件向 Xpert 宿主界面提供可交互视图的标准协议。它定义视图出现在哪里、何时可见、能够读取哪些数据、允许执行哪些操作，以及由哪种方式完成渲染。

对于 Assistant 工作台，远程组件（Remote Component）是视图扩展的一种渲染方式。它负责 iframe 中的自定义前端 UI；视图扩展负责宿主插槽、功能激活、权限、数据和操作等完整契约。

```text theme={null}
Assistant 功能
  -> 工作台视图宿主
  -> agent.workbench.main / agent.workbench.fixed
  -> ViewExtensionProvider
  -> XpertExtensionViewManifest
  -> 平台声明式渲染器或远程组件
```

## 核心概念

| 概念 | 职责 |
| - | - |
| 宿主（Host） | 提供可扩展的产品界面和当前用户上下文，例如 Assistant、项目或知识库 |
| 插槽（Slot） | 宿主中允许视图出现的位置，例如 `agent.workbench.main` |
| 视图提供器（View Provider） | 插件服务端实现，提供视图清单、数据、操作和可选的远程组件入口 |
| 视图清单（Manifest） | 声明视图的位置、激活条件、渲染方式和能力白名单 |
| 远程组件（Remote Component） | 在宿主控制的 iframe 中运行的插件自定义前端 UI |

远程组件不是独立的插件类型，也不能脱离视图清单单独注册。完整的工作台 UI 通常由服务端视图提供器和前端远程组件共同组成。

## 宿主与插槽

`hostType` 表示宿主类型。平台可以提供 `agent`、`project`、`knowledgebase`、`integration` 或 `sandbox` 等宿主。

Assistant 工作台使用 `agent` 宿主，常用插槽包括：

| 插槽 | 用途 |
| - | - |
| `agent.workbench.main` | 随当前工作台内容展示的主视图 |
| `agent.workbench.fixed` | 在工作台菜单中提供固定入口的视图 |
| `agent.profile.tabs` | Assistant 资料卡内按需加载的 tabs |
| `detail.sidebar` | 宿主详情页侧栏中的补充视图 |

插件只能向宿主已经声明的插槽提供视图。插槽描述产品位置，不应包含插件业务名称。

## 功能激活

Assistant 工作台插槽要求视图声明 `activation.requiredFeatures`。功能（Feature）是连接 Agent 能力和人类工作台界面的能力令牌：

```text theme={null}
Agent 中间件声明 Feature
  -> Assistant 连接该中间件
  -> 视图宿主获得功能
  -> 对应 View 才可见
```

```ts theme={null}
activation: {
  requiredFeatures: ['contract-review']
}
```

视图应依赖拥有其数据与操作的领域能力。移除对应中间件后，它提供的 Agent 工具和工作台视图应一起消失。

## 视图提供器

插件通过 `@ViewExtensionProvider(providerKey)` 注册视图提供器：

```ts theme={null}
import {
  type IXpertViewExtensionProvider,
  ViewExtensionProvider
} from '@xpert-ai/plugin-sdk'
import type {
  XpertExtensionViewManifest,
  XpertResolvedViewHostContext,
  XpertViewDataResult,
  XpertViewQuery
} from '@xpert-ai/contracts'

@ViewExtensionProvider('contract_review')
export class ContractReviewViewProvider
  implements IXpertViewExtensionProvider
{
  constructor(private readonly reviewService: ContractReviewService) {}

  supports(context: XpertResolvedViewHostContext) {
    return context.hostType === 'agent'
  }

  getViewManifests(
    _context: XpertResolvedViewHostContext,
    slot: string
  ): XpertExtensionViewManifest[] {
    if (slot !== 'agent.workbench.main') return []
    return [createContractReviewManifest(slot)]
  }

  async getViewData(
    context: XpertResolvedViewHostContext,
    viewKey: string,
    query: XpertViewQuery
  ): Promise<XpertViewDataResult> {
    return this.reviewService.getViewData(context, viewKey, query)
  }
}
```

提供器中的 `viewKey` 是本地清单键。平台公开的完整视图键为：

```text theme={null}
<providerKey>__<manifestKey>
```

例如 `contract_review` 提供器中的 `review` 视图，对外键为 `contract_review__review`。

## 选择渲染方式

视图清单的 `view.type` 决定渲染方式：

| 类型 | 适用场景 | UI 所有者 |
| - | - | - |
| `stats` | 少量指标概览 | 平台 |
| `table` | 标准表格、搜索、排序和分页 | 平台 |
| `list` | 标准列表 | 平台 |
| `detail` | 只读字段详情 | 平台 |
| `raw_json` | 调试或原始数据展示 | 平台 |
| `remote_component` | 编辑器、画布、复杂工作流或多面板工作台 | 插件 |

优先选择能满足需求的声明式视图。只有在交互和布局明显超出平台表格、列表或表单能力时，才使用远程组件。

## 视图清单是能力白名单

视图清单不仅描述页面，还声明远程组件能够使用的宿主能力：

| 清单字段 | 能力 |
| - | - |
| `dataSource` | 查询视图数据、分页、搜索、排序和参数支持 |
| `parameters` | 视图参数以及服务端提供的动态选项 |
| `actions` | JSON 操作或文件操作 |
| `fileAccess` | 预览或下载由提供器解析的文件 |
| `clientCommands` | 打开文件、导航或发送 Assistant 消息等宿主界面操作 |
| `hostEvents` | 接收工具完成等宿主侧事件 |
| `permissions` | 访问整个视图所需的权限 |

远程组件不能把宿主桥接当作任意远程调用通道。每项数据访问或操作都必须先在清单中声明，再由宿主和提供器执行。

## 打开方式与渲染方式彼此独立

视图可以由宿主枚举插槽后展示，也可以由工具结果中的 `xpert.extension_view` 按需打开。这只是入口不同，不会改变视图的清单、权限、数据提供器或远程组件实现。

工具结果只应携带公开视图键、初始查询和业务参数，不应包含访问令牌、API 地址、Assistant ID、租户 ID 或组织 ID。

## 安全边界

* 宿主根据已认证的服务端状态解析 `hostType`、`hostId`、租户、组织和用户。
* 清单由平台校验并按功能激活和权限过滤。
* 远程组件不接收访问令牌、平台 API 地址或宿主内部身份字段。
* 提供器必须重新校验业务权限，不能只信任 iframe 传入的业务 ID。
* JSON 操作用于有界结构化数据；文件和大对象使用专用能力。

## 下一步

* [工作台远程组件](./remote-component)：构建插件自定义工作台 UI。
* [远程组件宿主桥接](./remote-component-bridge)：查看消息、清单和提供器方法之间的映射。
* [运行时能力](./runtime-capabilities)：在插件服务端调用宿主提供的平台服务。

## Assistant Profile tabs

从 `@xpert-ai/contracts` 导入 `AGENT_PROFILE_TABS_SLOT`，向现有 `agent` host 注册视图。在 middleware metadata 中声明领域 Feature，每个 Profile manifest 都通过 `activation.requiredFeatures` 启用校验。同一 provider 可以同时提供 Workbench 与 Profile 视图。

```ts theme={null}
import { AGENT_PROFILE_TABS_SLOT, type XpertExtensionViewManifest } from '@xpert-ai/contracts'

const profileTab: XpertExtensionViewManifest = {
  key: 'recent-cases',
  title: { en_US: 'Recent cases', zh_Hans: '最近案件' },
  hostType: 'agent', slot: AGENT_PROFILE_TABS_SLOT,
  activation: { requiredFeatures: ['case-profile'] },
  view: {
    type: 'remote_component', runtime: 'react', protocolVersion: 1,
    dataSource: { mode: 'platform' },
    component: { isolation: 'iframe', entry: 'case-profile' }
  },
  dataSource: { mode: 'platform', cache: { enabled: false } },
  actions: [{ key: 'approve_and_continue', label: '批准并继续',
    actionType: 'invoke', placement: 'row', requiredHostAccess: 'read' }],
  clientCommands: [{ key: 'assistant.profile.interaction' }, { key: 'assistant.profile.close' }]
}
```

### 可信身份与权限

`getViewData(context, viewKey, query)` 和 `executeViewAction(context, viewKey, actionKey, request)` 接收 `XpertResolvedViewHostContext`。Agent host 的后端专用 `assistant` 字段包含：

| 字段 | 含义 |
| - | - |
| `instanceId` | 此 host 解析出的已发布 Assistant |
| `currentId` | 同一版本族中唯一的当前编辑实例；不存在时使用当前解析实例 |
| `versionIds` | 同一 Assistant 的版本身份集合，包含当前实例和发布版本 |

平台在租户、组织和工作空间边界内解析身份。不要根据名称、角色或相同模板推断实例。不要把 iframe query/action 中的 Assistant、用户、租户或组织 ID 当作授权依据。iframe 不接收认证信息，只通过 bridge 提交业务参数。

平台检查 host 访问、Feature、声明的 action 和 view session。**Assistant 对业务资源的访问权限由插件控制。** 工厂插件先将明确分配及执行参与记录，与当前人类用户可读的 Case Projects 取交集，再分页和统计。

服务端插件可以使用 `@xpert-ai/plugin-sdk` 的 `ProjectAccessRuntimeCapability`（`platform.project.access`），查询用户可读 Project（包含明确绑定的 `assistantIds`），通过 `assertManage` 校验 owner/manager 权限，或通过 `assertEdit` 校验 owner/manager/editor 权限。该能力供插件服务使用，不赋予 Agent 工具人类审批权。`requiredHostAccess: 'read'` 仅允许 Profile 读者进入 action 路由；插件必须再次校验具体案件的审批权限。

### 加载与决策生命周期

打开资料卡时获取基本资料和 manifests。扩展 tab 首次选中时实例化、查询并获取 view session，之后在资料卡打开期间保持挂载。切换 tab 时，宿主向隐藏的 Remote View 发送 `viewActive: false`；视图应暂停轮询、忽略过期响应，同时保留界面和数据状态。切回发送 `viewActive: true`，立即复用缓存数据，并从下一个轮询周期继续刷新。切换 Assistant 或关闭资料卡时释放全部缓存视图及 view session。基本资料接口 `GET /xpert/:id/profile` 返回展示白名单，不返回提示词、认证信息或完整 Assistant 图。

Profile Remote View 使用 opaque-origin iframe，不能读取 `localStorage` 或 `sessionStorage`。临时状态放在 React state 中，持久化状态通过 View actions 保存。

打开确认弹窗及提交期间，声明并调用 `assistant.profile.interaction`，传入 `{ busy: true }`，结束后传 `{ busy: false }`。宿主会保持卡片打开并禁止切换 tab。弹窗优先消费 Escape；没有弹窗和提交任务时，可调用 `assistant.profile.close` 关闭卡片并恢复焦点。销毁视图时一并注销命令作用域。

持久决策需携带业务版本和稳定的 operation ID。审批前展示方案和执行模式，审批与续跑意图在同一事务中保存，再通过 Managed Queue 和检查点推进。不要由浏览器编排后台续跑。工厂插件新增 `approve_and_continue`，保留原 `approve_recovery_plan` 语义，并始终使用 Factory Case 保存的协调 Assistant 派发验证任务，不替换成当前查看的专业 Assistant。
