Files
2026-09-02 11:44:52 +08:00

8.8 KiB
Raw Permalink Blame History

OpenNodes V1 — Update 示例、回写规则、错误模型和 writeSupport

本文件是 DWS OpenNodes V1 协议的拆分章节。按需读取入口见 协议索引

8. Update 示例

8.1 Append 一个文本节点

{
  "source": {
    "schemaVersion": "1.0",
    "catalogVersion": "dml-v1",
    "nodes": [
      {
        "id": "title",
        "type": "text",
        "x": 120,
        "y": 80,
        "width": 240,
        "height": 48,
        "text": {
          "blocks": [
            {
              "type": "paragraph",
              "horizontalAlign": "left",
              "runs": [
                {
                  "text": "Hello OpenNodes",
                  "marks": {
                    "fontSize": 16,
                    "color": "#223344"
                  }
                }
              ]
            }
          ],
          "verticalAlign": "center",
          "padding": [2, 4]
        }
      }
    ]
  }
}

8.2 Append 两个形状和一条引用连接线

{
  "source": {
    "schemaVersion": "1.0",
    "catalogVersion": "dml-v1",
    "nodes": [
      {
        "id": "left",
        "type": "shape",
        "x": 80,
        "y": 100,
        "width": 120,
        "height": 80,
        "geometry": "dml:roundRect"
      },
      {
        "id": "right",
        "type": "shape",
        "x": 360,
        "y": 100,
        "width": 120,
        "height": 80,
        "geometry": "dml:roundRect"
      },
      {
        "id": "line",
        "type": "connector",
        "start": {
          "type": "node",
          "nodeRef": {
            "scope": "request",
            "id": "left"
          },
          "anchor": {
            "mode": "fixed",
            "side": "right"
          }
        },
        "end": {
          "type": "node",
          "nodeRef": {
            "scope": "request",
            "id": "right"
          },
          "anchor": {
            "mode": "fixed",
            "side": "left"
          },
          "marker": {
            "catalogId": "arrow.filled"
          }
        },
        "routing": "straight"
      }
    ]
  }
}

8.3 Overwrite 整页

{
  "overwrite": true,
  "source": {
    "schemaVersion": "1.0",
    "catalogVersion": "dml-v1",
    "nodes": [
      {
        "id": "replacement",
        "type": "text",
        "x": 120,
        "y": 80,
        "width": 240,
        "height": 48,
        "text": {
          "blocks": [
            {
              "type": "paragraph",
              "runs": [
                {
                  "text": "Replacement content"
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

8.4 清空当前页面

{
  "overwrite": true,
  "source": {
    "schemaVersion": "1.0",
    "catalogVersion": "dml-v1",
    "nodes": []
  }
}

9. Query 数据不能直接回写

query 是完整可读投影,update 是受约束的创建协议,两者不是对称 JSON:

Query 字段/能力 Update 处理方式
真实 id 只能作为请求级临时 ID;不能引用既有 document 节点。
children 删除,通过子节点 parentId 重建。
absoluteBounds 删除;普通节点使用 x/y/width/height,connector 使用端点和路由字段。
lockedsourcewriteSupportunsupportedFeatures 删除,均为 query-only。
文本 plainText 删除,由服务端根据 paragraph 和 run 重新计算。
多 paragraph、列表、多 run、文字链接 可以保留;每个 block 必须是受支持类型,且 run 内不能包含原始换行符。
未知 list style、非法链接或未支持的 block/marks 需要移除或降级为受支持的 block/run。
theme paint 保留 token/lumMod/lumOff,删除 query-only resolvedColor;token 必须能在当前白板主题中解析。
image paint 需要降级成受支持的 paint,或不更新该节点。
受支持的 linear/radial gradient、单个 shadow 可以保留;gradient offset 使用 0100radial custom 不能回写。
blur、unknown 或叠加 effects 需要删除、降级成单个 shadow,或不更新该节点。
connector scope: "document" 不能回写;改为引用同一请求节点的 scope: "request"
connector resolvedPointpositionresolvedPath 删除,均由服务端重新计算。
shape adjustments V1 不支持写入。
stickyNote creatortags V1 不支持写入。

即使 query 节点显示 writeSupport = "readWrite",update 仍会对版本、目录、 字段和请求关系做完整校验。调用方不应跳过 update 错误处理。

10. 错误模型

10.1 顶层错误码

错误码 含义
invalidRequest.whiteboard.schemaInvalid JSON、字段或节点 schema 不合法。
invalidRequest.whiteboard.catalogVersionUnsupported catalogVersion 不受支持。
invalidRequest.whiteboard.validationFailed 节点间引用、父子关系或路径关系不合法。
invalidRequest.whiteboard.emptySource append 的 nodes 为空。
invalidRequest.whiteboard.overwriteUnsafe overwrite 安全预检失败。

10.2 DWS 错误输出

远端校验失败时,DWS 以统一 CLI 错误结构返回:

{
  "error": {
    "category": "api",
    "reason": "business_error",
    "server_key": "whiteboard",
    "server_error_code": "invalidRequest.whiteboard.validationFailed",
    "message": "Whiteboard request graph is invalid",
    "trace_id": "TRACE_ID"
  }
}

部分服务错误会使用更宽泛的 invalidRequest.inputArgs.invalid。Agent 应结合 server_error_codemessage 修正输入;需要排障时保留 trace_id。JSON 或 信封级错误可能由 CLI 本地返回,不一定包含 server_keytrace_id

校验类错误不可通过原样重试恢复。常见原因包括:

  • Schema:缺少字段、未知字段、类型或枚举值错误、提交 query-only 字段、 节点类型不支持。
  • 请求关系:临时 ID 重复、引用不存在、父子关系非法、连接线目标不支持、 路径退化或主题 token 不存在。
  • Overwrite 预检:锁定节点、禁止删除、关联数据无法安全处理或删除失败。

任一阶段失败都不会保留部分更新。

11. writeSupport 的含义

writeSupport 表示当前 query 节点是否能由 V1 update 无损表达,不代表用户 权限,也不代表 overwrite 是否允许移除该既有节点。

以下 unsupportedFeatures 均为对外返回的诊断枚举值:

  • node.source.masternode.lockednode.rolenode.placeholdernode.extrasnode.ability
  • node.type.imagenode.type.pdfnode.type.medianode.type.webLinknode.type.tablenode.type.chartnode.type.umlnode.type.swimlanenode.type.mindnode.type.timernode.type.placeholdernode.type.unknown
  • text.list.unsupportedtext.link.unsupportedtext.block.unsupportedtext.lineBreak.unsupportedtext.marks.unsupportedtext.color.unsupportedtext.highlight.unsupported
  • style.fill.colorstyle.fill.opacitystyle.fill.theme.tokenstyle.fill.theme.unresolvedstyle.fill.theme.modifierstyle.fill.theme.opacitystyle.fill.gradient.anglestyle.fill.gradient.offsetstyle.fill.gradient.colorstyle.fill.gradient.opacitystyle.fill.gradient.positionstyle.fill.image
  • style.stroke.colorstyle.stroke.opacitystyle.stroke.theme.tokenstyle.stroke.theme.unresolvedstyle.stroke.theme.modifierstyle.stroke.theme.opacitystyle.stroke.gradient.anglestyle.stroke.gradient.offsetstyle.stroke.gradient.colorstyle.stroke.gradient.opacitystyle.stroke.gradient.positionstyle.stroke.image
  • style.effects
  • shape.adjustmentsstickyNote.creatorstickyNote.tags
  • vector.resource.externalvector.resource.embeddedvector.resource.unresolvedvector.fillvector.strokevector.opacityvector.effectvector.adjustments
  • icon.catalogIdicon.opacityicon.effecticon.texticon.adjustments
  • path.commandspath.data.sizepath.commands.limitpath.textpath.fillRulepath.adjustments
  • connector.parentconnector.marker.unsupportedconnector.target.unexposedconnector.target.unsupportedconnector.anchor.unresolvedconnector.anchor.customconnector.selfLoop
  • group.anglegroup.children.minimumgroup.children.hiddengroup.child.readOnly
  • frame.angleframe.child.frameframe.child.readOnly

调用方应把 unsupportedFeatures 当作诊断信息,不应把当前枚举穷举写死为 业务逻辑。真正可写与否以 writeSupport 和 update 校验结果为准。