Parcourir la source

feat(openapi): 规格加入 /v3/agent-grants;discussions 支持批注与 AI 代写

- 新增 POST /v3/agent-grants:人类为自己名下的 AI 模型签 channel 写入授权
- discussions:type 增加 note / commentary(批注),列表与 summary 不带 type 时只算
  评论线程;批注锚点字段 pos_* / quote_*;响应新增 co_editor;写入支持 X-Agent-Grant
- delete 权限放开为作者或挂靠对象的管理者

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
visuddhinanda il y a 4 jours
Parent
commit
3f635b2afa

+ 2 - 0
openapi/public/assets/protocol/main.yaml

@@ -681,6 +681,8 @@ paths:
     $ref: ./resources/auto/v2-webhook.yaml
   '/v2/webhook/{webhook}':
     $ref: ./resources/auto/v2-webhook-webhook.yaml
+  /v3/agent-grants:
+    $ref: ./resources/auto/v3-agent-grants.yaml
   /v3/discussions:
     $ref: ./resources/auto/v3-discussions.yaml
   /v3/discussions/summary:

+ 102 - 0
openapi/public/assets/protocol/resources/auto/v3-agent-grants.yaml

@@ -0,0 +1,102 @@
+# 由 openapi/scripts/generate.php 生成,请勿手改;补充写到 overrides/v3-agent-grants.yaml
+post:
+  summary: '签发 agent 写入授权'
+  tags:
+    - agent-grants
+  operationId: post_api_v3_agent_grants
+  description: |-
+    必须用人类的登录 token 调用(模型 token 403);模型必须归当前用户所有,当前用户
+    必须能编辑该 channel。授权 7 天有效,只能由指定的模型使用;撤销该模型的 token
+    (token_version 自增)时一并失效。
+    模型写入时用自己的模型 token 登录,并带请求头 `X-Agent-Grant: <token>`;
+    写入的记录 editor 为授权人、co_editor 为模型,权限按授权人判断。
+
+    实现:`V3\AgentGrantController@store`
+  security:
+    -
+      bearerAuth: []
+  requestBody:
+    required: true
+    content:
+      application/json:
+        schema:
+          type: object
+          properties:
+            ai_model:
+              type: string
+              description: '被授权的 AI 模型 uid'
+            target_type:
+              type: string
+              description: 授权范围的类型
+              enum:
+                - channel
+            target_id:
+              type: string
+              description: 'channel 的 uid'
+            book:
+              type: integer
+              description: '限定 book,0 或不传表示不限'
+              default: 0
+          required:
+            - ai_model
+            - target_type
+            - target_id
+  responses:
+    200:
+      description: 成功
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              data:
+                type: object
+                properties:
+                  token:
+                    type: string
+                  grantor:
+                    type: string
+                  ai_model:
+                    type: string
+                  target_type:
+                    type: string
+                  target_id:
+                    type: string
+                  book:
+                    type: integer
+                  expires_at:
+                    type: string
+    201:
+      description: 签发成功
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              data:
+                type: object
+                properties:
+                  token:
+                    type: string
+                  grantor:
+                    type: string
+                  ai_model:
+                    type: string
+                  target_type:
+                    type: string
+                  target_id:
+                    type: string
+                  book:
+                    type: integer
+                  expires_at:
+                    type: string
+    401:
+      $ref: '../../main.yaml#/components/responses/ProblemUnauthorized'
+    403:
+      description: '用模型 token 调用、模型不归当前用户,或当前用户不能编辑该 channel'
+      content:
+        application/problem+json:
+          schema:
+            $ref: '../../main.yaml#/components/schemas/ProblemDetails'
+    422:
+      $ref: '../../main.yaml#/components/responses/ProblemValidation'

+ 72 - 0
openapi/public/assets/protocol/resources/auto/v3-discussions-discussion-replies.yaml

@@ -80,6 +80,21 @@ get:
                     tpl_id:
                       type: string
                       nullable: true
+                    pos_start:
+                      type: integer
+                      nullable: true
+                    pos_end:
+                      type: integer
+                      nullable: true
+                    quote_exact:
+                      type: string
+                      nullable: true
+                    quote_prefix:
+                      type: string
+                      nullable: true
+                    quote_suffix:
+                      type: string
+                      nullable: true
                     reply_count:
                       type: integer
                       description: 仅在部分查询口径下返回。
@@ -87,6 +102,10 @@ get:
                       type: object
                       properties: { id: { type: string }, nickName: { type: string }, userName: { type: string }, realName: { type: string }, sn: { type: integer }, avatar: { type: string }, roles: { type: array, items: { type: string } } }
                       nullable: true
+                    co_editor:
+                      type: object
+                      properties: { id: { type: string }, nickName: { type: string }, userName: { type: string }, realName: { type: string }, sn: { type: integer }, avatar: { type: string }, roles: { type: array, items: { type: string } } }
+                      nullable: true
                     abilities:
                       type: object
                       properties: { update: { type: boolean }, delete: { type: boolean }, close: { type: boolean }, reply: { type: boolean } }
@@ -108,6 +127,7 @@ post:
   operationId: post_api_v3_discussions_discussion_replies
   description: |-
     类型与挂靠对象继承话题。已关闭的话题不能回复(409),对一条回复再回复 422。
+    AI 代写同 `POST /v3/discussions`(`X-Agent-Grant` 请求头)。
     文章上的 qa 只有文章的编辑者能回答。默认发通知,`notify=false` 关闭。
 
     实现:`V3\DiscussionReplyController@store`
@@ -182,6 +202,21 @@ post:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -196,6 +231,17 @@ post:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:
@@ -253,6 +299,21 @@ post:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -267,6 +328,17 @@ post:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:

+ 103 - 3
openapi/public/assets/protocol/resources/auto/v3-discussions-discussion.yaml

@@ -65,6 +65,21 @@ get:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -79,6 +94,17 @@ get:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:
@@ -101,7 +127,8 @@ delete:
     - discussions
   operationId: delete_api_v3_discussions_discussion_
   description: |-
-    目前只有作者本人能删。删话题不动回复:有回复的话题以墓碑形式留在列表里。
+    作者本人或挂靠对象的管理者(句子 / 逐词所在 channel、文章的编辑者)能删;
+    v2 只允许作者。删话题不动回复:有回复的话题以墓碑形式留在列表里。
     返回删除后的资源(200),不是 204——软删的资源并没有消失。
 
     实现:`V3\DiscussionController@destroy`
@@ -160,6 +187,21 @@ delete:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -174,6 +216,17 @@ delete:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:
@@ -191,7 +244,7 @@ delete:
     401:
       $ref: '../../main.yaml#/components/responses/ProblemUnauthorized'
     403:
-      description: 只能删除自己发表的内容
+      description: 既不是作者,也不是挂靠对象的管理者
       content:
         application/problem+json:
           schema:
@@ -207,6 +260,10 @@ patch:
     只改传了的字段。title / status / type / severity 只对话题有效,回复传了 422。
     作者或对象的管理者(句子、逐词所在 channel 的编辑者,文章的编辑者)可改;
     改 type 时回复跟着改,新类型不收原来的 severity 时 severity 清空。
+    批注:没有 status,type 只能在 note / commentary 之间改(不能与评论线程互转),
+    正文不能清空,可改锚点。
+    改了内容(标题、正文、锚点)时 co_editor 跟着这次写入走:人亲自改则清空,AI 代改则换成该模型;
+    只改 status / type / severity 不动 co_editor。
 
     实现:`V3\DiscussionController@update`
   security:
@@ -241,12 +298,14 @@ patch:
                 - close
             type:
               type: string
-              description: 话题类型(只限话题)
+              description: 类型(只限话题;评论线程与批注不能互转)
               enum:
                 - discussion
                 - qa
                 - help
                 - issue
+                - note
+                - commentary
             severity:
               type: string
               description: '严重程度(只限话题),null 表示清空'
@@ -256,6 +315,21 @@ patch:
                 - info
                 - urgent
                 - normal
+            pos_start:
+              type: integer
+              description: 锚点起始偏移(只限批注)
+            pos_end:
+              type: integer
+              description: 锚点结束偏移(只限批注)
+            quote_exact:
+              type: string
+              description: 锚定的原文片段(只限批注)
+            quote_prefix:
+              type: string
+              description: 锚定片段前的上下文(只限批注)
+            quote_suffix:
+              type: string
+              description: 锚定片段后的上下文(只限批注)
   responses:
     200:
       description: 成功
@@ -300,6 +374,21 @@ patch:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -314,6 +403,17 @@ patch:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:

+ 3 - 1
openapi/public/assets/protocol/resources/auto/v3-discussions-summary.yaml

@@ -44,7 +44,9 @@ get:
           - qa
           - help
           - issue
-      description: 只数这种类型的话题
+          - note
+          - commentary
+      description: 只数这种类型,不传则只数评论线程
   responses:
     200:
       description: 成功

+ 100 - 7
openapi/public/assets/protocol/resources/auto/v3-discussions.yaml

@@ -8,6 +8,7 @@ get:
     只列话题(不含回复),删除了但还有回复的话题以墓碑出现(deleted_at 有值、内容为空)。
     未登录看不到协作类话题(discussion / issue);basic 角色在自己无权管理的对象上只看得到
     自己发起的协作类话题。各状态的数量与「能发起哪些类型」见 `GET /v3/discussions/summary`。
+    不传 type 时只列评论线程(discussion / qa / help / issue),批注要显式 type=note / commentary。
 
     实现:`V3\DiscussionController@index`
   security:
@@ -52,7 +53,9 @@ get:
           - qa
           - help
           - issue
-      description: 话题类型
+          - note
+          - commentary
+      description: 类型,不传则只列评论线程
     -
       name: status
       in: query
@@ -134,6 +137,21 @@ get:
                     tpl_id:
                       type: string
                       nullable: true
+                    pos_start:
+                      type: integer
+                      nullable: true
+                    pos_end:
+                      type: integer
+                      nullable: true
+                    quote_exact:
+                      type: string
+                      nullable: true
+                    quote_prefix:
+                      type: string
+                      nullable: true
+                    quote_suffix:
+                      type: string
+                      nullable: true
                     reply_count:
                       type: integer
                       description: 仅在部分查询口径下返回。
@@ -141,6 +159,10 @@ get:
                       type: object
                       properties: { id: { type: string }, nickName: { type: string }, userName: { type: string }, realName: { type: string }, sn: { type: integer }, avatar: { type: string }, roles: { type: array, items: { type: string } } }
                       nullable: true
+                    co_editor:
+                      type: object
+                      properties: { id: { type: string }, nickName: { type: string }, userName: { type: string }, realName: { type: string }, sn: { type: integer }, avatar: { type: string }, roles: { type: array, items: { type: string } } }
+                      nullable: true
                     abilities:
                       type: object
                       properties: { update: { type: boolean }, delete: { type: boolean }, close: { type: boolean }, reply: { type: boolean } }
@@ -156,7 +178,7 @@ get:
     422:
       $ref: '../../main.yaml#/components/responses/ProblemValidation'
 post:
-  summary: 发起话题
+  summary: 发起话题或新建批注
   tags:
     - discussions
   operationId: post_api_v3_discussions
@@ -164,6 +186,9 @@ post:
     discussion / issue 登录即可发;qa / help 只能发在文章上,且只有文章的编辑者能发。
     severity 的取值随 type:issue 为 error / warning / info,help 为 urgent / normal,
     其它类型不收。默认会通知对象的作者(站内信 + webhook),`notify=false` 关闭。
+    批注(note / commentary)只能加在句子上,且只有该句所在 channel 的编辑者能加;
+    标题可省、正文必填,commentary 的正文必须是义注句子模板 `{{book-para-start-end}}`
+    (可多句并列);可带锚点 pos_* / quote_*(评论线程传了 422);不发通知。
 
     实现:`V3\DiscussionController@store`
   security:
@@ -190,19 +215,21 @@ post:
               description: '挂靠对象的 uuid'
             type:
               type: string
-              description: 话题类型
+              description: 类型
               enum:
                 - discussion
                 - qa
                 - help
                 - issue
+                - note
+                - commentary
               default: discussion
             title:
               type: string
-              description: '标题,最长 256 字符'
+              description: '标题,最长 256 字符;评论线程必填,批注可省'
             content:
               type: string
-              description: 正文(markdown)
+              description: 正文(markdown);批注必填
             severity:
               type: string
               description: 严重程度
@@ -212,17 +239,31 @@ post:
                 - info
                 - urgent
                 - normal
+            pos_start:
+              type: integer
+              description: 批注锚点在句子文本中的起始偏移(只限批注)
+            pos_end:
+              type: integer
+              description: 批注锚点的结束偏移,批注插在这里(只限批注)
+            quote_exact:
+              type: string
+              description: 锚定的原文片段(只限批注)
+            quote_prefix:
+              type: string
+              description: 锚定片段前的上下文,用于重新定位(只限批注)
+            quote_suffix:
+              type: string
+              description: 锚定片段后的上下文,用于重新定位(只限批注)
             tpl_id:
               type: string
               description: '话题模板(文章)的 uuid'
             notify:
               type: boolean
-              description: 是否发通知
+              description: 是否发通知(批注不发)
               default: true
           required:
             - target_type
             - target_id
-            - title
   responses:
     200:
       description: 成功
@@ -267,6 +308,21 @@ post:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -281,6 +337,17 @@ post:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties:
@@ -338,6 +405,21 @@ post:
                   tpl_id:
                     type: string
                     nullable: true
+                  pos_start:
+                    type: integer
+                    nullable: true
+                  pos_end:
+                    type: integer
+                    nullable: true
+                  quote_exact:
+                    type: string
+                    nullable: true
+                  quote_prefix:
+                    type: string
+                    nullable: true
+                  quote_suffix:
+                    type: string
+                    nullable: true
                   reply_count:
                     type: integer
                     description: 仅在部分查询口径下返回。
@@ -352,6 +434,17 @@ post:
                       avatar: { type: string }
                       roles: { type: array, items: { type: string } }
                     nullable: true
+                  co_editor:
+                    type: object
+                    properties:
+                      id: { type: string }
+                      nickName: { type: string }
+                      userName: { type: string }
+                      realName: { type: string }
+                      sn: { type: integer }
+                      avatar: { type: string }
+                      roles: { type: array, items: { type: string } }
+                    nullable: true
                   abilities:
                     type: object
                     properties: