Skip to Content
API 參考複合指令

複合指令

複合指令是一支已儲存的程式,能在同一個交易內跨多張自訂資料表寫入。你只需建置一次——具型別的 inputs、有序的步驟、宣告的 outputs——之後每次呼叫都是全部提交或全部回滾,呼叫端不必為了「訂單只寫了一半」再自己寫補償邏輯。

建置的門檻刻意高於呼叫。建立指令必須指定標籤,定義中觸及的每一張資料表都要掛在該標籤下,而且你必須有管理權。執行時則只需要對這些資料表的讀取權,加上各步驟本身所需的權限——正因如此,你才能把一個範圍明確、留有稽核紀錄的寫入動作,交給沒有能力自行建置它的人。

Dependency refresh 有兩種政策。一般 column/rule/IaC/purge-repair mutation 只在 mutation 的 commit 內刷新 selected、先前 valid 且仍可編譯的 command;DBAPIError 以外的 failure 會降級或略過,mutation 優先,command 保持 stale。Multi-table purge/repair probe 依 rewritten table 自己的 scope 分組;這種分組是完整的,因為 command contract 採 exact-scope-closed:每個 closure member 都必須通過 command 的精確 scope filter,跨 scope authoring 則以 A referenced table does not exist in this scope 失敗。每個 participating scope 都會收到完整的 rewritten-table set。透過 no-dependent fast path 併發建立的新 command,仍可能依 mutation 前形狀編譯並落成 stale。Trigger write 會先驗證 candidate graph,並要求所有 selected refresh 成功;trigger、history、IaC state 與 refreshed definitions 原子提交,失敗則以 command_dependency_refresh_failed 回滾 trigger mutation。兩種政策都不修復原本已 stale 的 command。

呼叫指令有兩條通道。/execute 是交易式寫入通道:它會保留 idempotency key、遇到 require_approval 規則時把整份計畫暫存並回應 409 approval_required,並留下可回頭查閱的執行稽核紀錄。/query 則是給 mode: "query" 指令的唯讀通道——不上鎖、以 cursor 分頁、沒有重播 key,也不留執行紀錄。走錯通道會得到 409,不會默默執行。

除了三個範圍路由之外,還有一條位於 /agent/commands/… 的 agent 通道。它沒有範圍區段:由服務 token 驗證呼叫端,再以伺服器注入的 header 綁定唯一的 principal,指令的範圍與 acting room 都由此推導。這條路由刻意不出現在 OpenAPI,也不是瀏覽器整合介面。

Agent execute 還要求伺服器注入 X-TeamSync-Agent-Channel。選填的 X-TeamSync-Agent-Group-Scope 是 64 個小寫十六進位字元的 digest,而且只有 channel 是 line_groupline_room 時才必填;其他 channel 一律不得出現。具型別 header 缺漏或格式錯誤時,request validation 會回 422;格式正確但出現條件組合錯誤時,則回 400 {"detail":{"error":"invalid_agent_group_scope"}}。這些 header 會參與授權、idempotency 與 delivery identity,模型絕不可自行產生。

在人工 scoped REST 上,expected_contract_digest 是選填的 request 欄位。動態生成的 write-command 工具則把它保留為伺服器私有值,不會放進模型可見的 schema;使用者在後續以明確自然語言同意後,伺服器 adapter 才會注入從建置後 command definition 釘選的 digest。Query 模式工具不使用此欄位。

POST
路由範本/private/module/custom_tables/{scopeWithId}/commands

建立複合指令

用途

在單一範圍內存放一支具名的有序步驟程式,於同一個交易內跨多張資料表寫入。

適用時機

當一個商業動作必須同時異動多張資料表、而且「只成功一半」會弄壞資料時使用,例如建立訂單同時扣庫存、建立預約同時佔用時段。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands
  • 部門/private/module/custom_tables/department/{department_id}/commands
  • 公司/private/module/custom_tables/company/{company_id}/commands

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

請求結構

CommandCreateRequest
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command. When False the command stays fully usable over REST but is never loaded as an agent tool.
definitionCommandDefinition-InputTyped inputs and ordered multi-table write steps.
descriptionstringHuman-readable purpose and usage notes.
namestringCommand display name; unique within its scope.
tag_idstringRequired tag from the same custom-table scope. Every referenced table must currently be assigned to this tag.

回應結構

CommandResponse
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command.
chatroom_idstring | nullChatroom scope id
company_idstring | nullCompany scope id
created_atstring (date-time)未指定
created_bystring未指定
definitionCommandDefinition-OutputFull command definition DSL body stored in CustomTableCommand.definition.
department_idstring | nullDepartment scope id
descriptionstring未指定
idstringCommand UUID
is_deletedbooleanSoft-delete marker
lifecycle_redactedbooleanTrue when callback and lifecycle-trigger configuration is omitted because the caller can execute but cannot manage every target table.
namestring未指定
tag_idstring | null未指定
updated_atstring (date-time)未指定

範例

建立「下訂單並扣庫存」指令

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111"
  },
  "body": {
    "name": "建立訂單並扣庫存",
    "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。",
    "agent_enabled": true,
    "tag_id": "33333333-3333-4333-8333-333333333333",
    "definition": {
      "version": 2,
      "inputs": [
        {
          "name": "customer",
          "type": "string",
          "required": true,
          "max_length": 100,
          "description": "客戶名稱"
        },
        {
          "name": "item",
          "type": "string",
          "required": true,
          "max_length": 100,
          "description": "品項名稱"
        },
        {
          "name": "quantity",
          "type": "integer",
          "required": true,
          "description": "出貨數量"
        }
      ],
      "steps": [
        {
          "kind": "select",
          "name": "stock",
          "from": {
            "table": "55555555-5555-4555-8555-555555555555",
            "as": "s"
          },
          "select": {
            "id": "$row.s.id",
            "on_hand": "$row.s.庫存"
          },
          "where": {
            "$and": [
              {
                "$eq": [
                  "$row.s.品項",
                  "$input.item"
                ]
              }
            ]
          },
          "max_rows": 1
        },
        {
          "kind": "let",
          "name": "on_hand",
          "type": "integer",
          "value": {
            "$single": {
              "relation": "$rel.stock",
              "expr": "$item.on_hand"
            }
          }
        },
        {
          "kind": "assert",
          "name": "stock_ok",
          "condition": {
            "$gte": [
              "$var.on_hand",
              "$input.quantity"
            ]
          },
          "message": "庫存不足,無法建立訂單"
        },
        {
          "kind": "insert",
          "name": "order",
          "table": "44444444-4444-4444-8444-444444444444",
          "values": {
            "客戶": "$input.customer",
            "品項": "$input.item",
            "數量": "$input.quantity",
            "狀態": "draft",
            "建立者": "$ctx.user_id"
          },
          "returning": {
            "id": "$new.id"
          }
        },
        {
          "kind": "update",
          "name": "consume",
          "table": "55555555-5555-4555-8555-555555555555",
          "for_each": "$rel.stock",
          "set": {
            "庫存": {
              "$sub": [
                "$item.on_hand",
                "$input.quantity"
              ]
            }
          },
          "match": {
            "id": "$item.id"
          },
          "max_rows": 1,
          "returning": {
            "id": "$new.id"
          }
        }
      ],
      "outputs": {
        "order_id": {
          "value": {
            "$single": {
              "relation": "$rel.order",
              "expr": "$item.id"
            }
          }
        },
        "remaining": {
          "value": {
            "$sub": [
              "$var.on_hand",
              "$input.quantity"
            ]
          }
        }
      }
    }
  }
}
回應200
{
  "id": "22222222-2222-4222-8222-222222222222",
  "name": "建立訂單並扣庫存",
  "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。",
  "agent_enabled": true,
  "definition": {
    "version": 2,
    "inputs": [
      {
        "name": "customer",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "客戶名稱"
      },
      {
        "name": "item",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "品項名稱"
      },
      {
        "name": "quantity",
        "type": "integer",
        "required": true,
        "description": "出貨數量"
      }
    ],
    "steps": [
      {
        "kind": "select",
        "name": "stock",
        "from": {
          "table": "55555555-5555-4555-8555-555555555555",
          "as": "s"
        },
        "select": {
          "id": "$row.s.id",
          "on_hand": "$row.s.庫存"
        },
        "where": {
          "$and": [
            {
              "$eq": [
                "$row.s.品項",
                "$input.item"
              ]
            }
          ]
        },
        "max_rows": 1
      },
      {
        "kind": "let",
        "name": "on_hand",
        "type": "integer",
        "value": {
          "$single": {
            "relation": "$rel.stock",
            "expr": "$item.on_hand"
          }
        }
      },
      {
        "kind": "assert",
        "name": "stock_ok",
        "condition": {
          "$gte": [
            "$var.on_hand",
            "$input.quantity"
          ]
        },
        "message": "庫存不足,無法建立訂單"
      },
      {
        "kind": "insert",
        "name": "order",
        "table": "44444444-4444-4444-8444-444444444444",
        "values": {
          "客戶": "$input.customer",
          "品項": "$input.item",
          "數量": "$input.quantity",
          "狀態": "draft",
          "建立者": "$ctx.user_id"
        },
        "returning": {
          "id": "$new.id"
        }
      },
      {
        "kind": "update",
        "name": "consume",
        "table": "55555555-5555-4555-8555-555555555555",
        "for_each": "$rel.stock",
        "set": {
          "庫存": {
            "$sub": [
              "$item.on_hand",
              "$input.quantity"
            ]
          }
        },
        "match": {
          "id": "$item.id"
        },
        "max_rows": 1,
        "returning": {
          "id": "$new.id"
        }
      }
    ],
    "outputs": {
      "order_id": {
        "value": {
          "$single": {
            "relation": "$rel.order",
            "expr": "$item.id"
          }
        }
      },
      "remaining": {
        "value": {
          "$sub": [
            "$var.on_hand",
            "$input.quantity"
          ]
        }
      }
    }
  },
  "tag_id": "33333333-3333-4333-8333-333333333333",
  "chatroom_id": "11111111-1111-4111-8111-111111111111",
  "department_id": null,
  "company_id": null,
  "created_by": "77777777-7777-4777-8777-777777777777",
  "created_at": "2026-07-21T02:10:00",
  "updated_at": "2026-07-21T02:10:00",
  "is_deleted": false,
  "lifecycle_redacted": false
}

錯誤

狀態發生條件錯誤本文
400definition 未通過建置驗證;errors 會列出所有問題,例如 callback URL 指向不被允許的主機。
{
  "detail": {
    "error": "invalid_command_definition",
    "errors": [
      "callback 'notify': URL host is not allowed"
    ]
  }
}
403請求使用 UserAPIKey 而非 JWT 驗證。
{
  "detail": "Custom-table command routes require JWT authentication"
}
404步驟引用了此範圍內不存在的資料表,或呼叫者無權管理的資料表;兩種情況回傳相同內容。
{
  "detail": "Referenced table not found in this scope"
}
404tag_id 不是此範圍內的標籤。
{
  "detail": "Tag not found in this scope"
}
409此範圍內已有同名的活指令。自 2026-07-28 起,刪除的指令會立即釋放名字,所以只有活的持有者會撞名。
{
  "detail": {
    "error": "command_name_conflict",
    "name": "建立訂單並扣庫存"
  }
}
409兩筆編寫寫入爭用同一個指令範圍,InnoDB 中止了這一筆。交易已回滾,沒有任何指令被建立——直接重送請求即可。
{
  "detail": "Concurrent write conflict (lock); please retry the request."
}
422引用的資料表目前未掛在 tag_id 上;table_ids 會列出不符合的資料表。
{
  "detail": {
    "error": "command_tables_outside_tag",
    "tag_id": "33333333-3333-4333-8333-333333333333",
    "table_ids": [
      "55555555-5555-4555-8555-555555555555"
    ]
  }
}
422編譯後的定義完全沒有引用任何自訂資料表——只有 let、只有 callback,或根本沒有 step。在這道閘門之前,同樣的 body 會回 201 並存下一支讓所有權限檢查都視為無害的指令。
{
  "detail": {
    "error": "command_references_no_table",
    "message": "a command must reference at least one custom table in this scope"
  }
}
GET
路由範本/private/module/custom_tables/{scopeWithId}/commands

列出範圍內的指令

用途

回傳此範圍內、呼叫者對每一張被引用資料表都有讀取權的指令,依建立時間新到舊排序。

適用時機

適合用來建立指令選單,或在把按鈕接上某支指令前,確認特定使用者實際看得到哪些複合動作。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands
  • 部門/private/module/custom_tables/department/{department_id}/commands
  • 公司/private/module/custom_tables/company/{company_id}/commands

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
skipqueryint >= 0略過前幾筆可見指令,預設為 0。
limitqueryint 1..200最多回傳幾筆指令,可填 1 到 200,預設為 50。

回應結構

CommandListResponse
欄位型別必填說明
itemsCommandResponse[]未指定
totalinteger未指定

範例

列出聊天室中第一頁指令

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111"
  },
  "query": {
    "skip": "0",
    "limit": "20"
  }
}
回應200
{
  "items": [
    {
      "id": "22222222-2222-4222-8222-222222222222",
      "name": "建立訂單並扣庫存",
      "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。",
      "agent_enabled": true,
      "definition": {
        "version": 2,
        "inputs": [
          {
            "name": "customer",
            "type": "string",
            "required": true,
            "max_length": 100,
            "description": "客戶名稱"
          },
          {
            "name": "item",
            "type": "string",
            "required": true,
            "max_length": 100,
            "description": "品項名稱"
          },
          {
            "name": "quantity",
            "type": "integer",
            "required": true,
            "description": "出貨數量"
          }
        ],
        "steps": [
          {
            "kind": "select",
            "name": "stock",
            "from": {
              "table": "55555555-5555-4555-8555-555555555555",
              "as": "s"
            },
            "select": {
              "id": "$row.s.id",
              "on_hand": "$row.s.庫存"
            },
            "where": {
              "$and": [
                {
                  "$eq": [
                    "$row.s.品項",
                    "$input.item"
                  ]
                }
              ]
            },
            "max_rows": 1
          },
          {
            "kind": "let",
            "name": "on_hand",
            "type": "integer",
            "value": {
              "$single": {
                "relation": "$rel.stock",
                "expr": "$item.on_hand"
              }
            }
          },
          {
            "kind": "assert",
            "name": "stock_ok",
            "condition": {
              "$gte": [
                "$var.on_hand",
                "$input.quantity"
              ]
            },
            "message": "庫存不足,無法建立訂單"
          },
          {
            "kind": "insert",
            "name": "order",
            "table": "44444444-4444-4444-8444-444444444444",
            "values": {
              "客戶": "$input.customer",
              "品項": "$input.item",
              "數量": "$input.quantity",
              "狀態": "draft",
              "建立者": "$ctx.user_id"
            },
            "returning": {
              "id": "$new.id"
            }
          },
          {
            "kind": "update",
            "name": "consume",
            "table": "55555555-5555-4555-8555-555555555555",
            "for_each": "$rel.stock",
            "set": {
              "庫存": {
                "$sub": [
                  "$item.on_hand",
                  "$input.quantity"
                ]
              }
            },
            "match": {
              "id": "$item.id"
            },
            "max_rows": 1,
            "returning": {
              "id": "$new.id"
            }
          }
        ],
        "outputs": {
          "order_id": {
            "value": {
              "$single": {
                "relation": "$rel.order",
                "expr": "$item.id"
              }
            }
          },
          "remaining": {
            "value": {
              "$sub": [
                "$var.on_hand",
                "$input.quantity"
              ]
            }
          }
        }
      },
      "tag_id": "33333333-3333-4333-8333-333333333333",
      "chatroom_id": "11111111-1111-4111-8111-111111111111",
      "department_id": null,
      "company_id": null,
      "created_by": "77777777-7777-4777-8777-777777777777",
      "created_at": "2026-07-21T02:10:00",
      "updated_at": "2026-07-21T02:10:00",
      "is_deleted": false,
      "lifecycle_redacted": false
    }
  ],
  "total": 1
}

錯誤

狀態發生條件錯誤本文
403請求使用 UserAPIKey 而非 JWT 驗證。
{
  "detail": "Custom-table command routes require JWT authentication"
}
403聊天室範圍的呼叫者既不是該聊天室成員,角色也不足以代行成員權限。
{
  "detail": "Insufficient permissions, not a member (Required department manager)."
}
404路徑上的公司或部門屬於其他租戶。這裡回 404 而非 403,避免此 id 變成存在性探測工具。
{
  "detail": "Company not found"
}
GET
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}

取得單一指令

用途

回傳一支已儲存的指令,含完整 definition、標籤與範圍 id。

適用時機

在製作呼叫表單前先讀取,才能知道每個宣告的 input 名稱、型別,以及是否必填。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要讀取的指令 UUID。

回應結構

CommandResponse
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command.
chatroom_idstring | nullChatroom scope id
company_idstring | nullCompany scope id
created_atstring (date-time)未指定
created_bystring未指定
definitionCommandDefinition-OutputFull command definition DSL body stored in CustomTableCommand.definition.
department_idstring | nullDepartment scope id
descriptionstring未指定
idstringCommand UUID
is_deletedbooleanSoft-delete marker
lifecycle_redactedbooleanTrue when callback and lifecycle-trigger configuration is omitted because the caller can execute but cannot manage every target table.
namestring未指定
tag_idstring | null未指定
updated_atstring (date-time)未指定

範例

在呼叫前讀取指令定義

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222"
  }
}
回應200
{
  "id": "22222222-2222-4222-8222-222222222222",
  "name": "建立訂單並扣庫存",
  "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。",
  "agent_enabled": true,
  "definition": {
    "version": 2,
    "inputs": [
      {
        "name": "customer",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "客戶名稱"
      },
      {
        "name": "item",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "品項名稱"
      },
      {
        "name": "quantity",
        "type": "integer",
        "required": true,
        "description": "出貨數量"
      }
    ],
    "steps": [
      {
        "kind": "select",
        "name": "stock",
        "from": {
          "table": "55555555-5555-4555-8555-555555555555",
          "as": "s"
        },
        "select": {
          "id": "$row.s.id",
          "on_hand": "$row.s.庫存"
        },
        "where": {
          "$and": [
            {
              "$eq": [
                "$row.s.品項",
                "$input.item"
              ]
            }
          ]
        },
        "max_rows": 1
      },
      {
        "kind": "let",
        "name": "on_hand",
        "type": "integer",
        "value": {
          "$single": {
            "relation": "$rel.stock",
            "expr": "$item.on_hand"
          }
        }
      },
      {
        "kind": "assert",
        "name": "stock_ok",
        "condition": {
          "$gte": [
            "$var.on_hand",
            "$input.quantity"
          ]
        },
        "message": "庫存不足,無法建立訂單"
      },
      {
        "kind": "insert",
        "name": "order",
        "table": "44444444-4444-4444-8444-444444444444",
        "values": {
          "客戶": "$input.customer",
          "品項": "$input.item",
          "數量": "$input.quantity",
          "狀態": "draft",
          "建立者": "$ctx.user_id"
        },
        "returning": {
          "id": "$new.id"
        }
      },
      {
        "kind": "update",
        "name": "consume",
        "table": "55555555-5555-4555-8555-555555555555",
        "for_each": "$rel.stock",
        "set": {
          "庫存": {
            "$sub": [
              "$item.on_hand",
              "$input.quantity"
            ]
          }
        },
        "match": {
          "id": "$item.id"
        },
        "max_rows": 1,
        "returning": {
          "id": "$new.id"
        }
      }
    ],
    "outputs": {
      "order_id": {
        "value": {
          "$single": {
            "relation": "$rel.order",
            "expr": "$item.id"
          }
        }
      },
      "remaining": {
        "value": {
          "$sub": [
            "$var.on_hand",
            "$input.quantity"
          ]
        }
      }
    }
  },
  "tag_id": "33333333-3333-4333-8333-333333333333",
  "chatroom_id": "11111111-1111-4111-8111-111111111111",
  "department_id": null,
  "company_id": null,
  "created_by": "77777777-7777-4777-8777-777777777777",
  "created_at": "2026-07-21T02:10:00",
  "updated_at": "2026-07-21T02:10:00",
  "is_deleted": false,
  "lifecycle_redacted": false
}

錯誤

狀態發生條件錯誤本文
403請求使用 UserAPIKey 而非 JWT 驗證。
{
  "detail": "Custom-table command routes require JWT authentication"
}
404指令不存在於此範圍、已被軟刪除,或引用了呼叫者無法讀取的資料表。
{
  "detail": "Command not found"
}
PUT
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}

取代指令定義

用途

整支取代指令的名稱、說明、標籤與 definition,並依即時 schema 重新驗證。

適用時機

當指令背後的商業規則改變,或它寫入的資料表新增了必須填寫的欄位時使用。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要取代的指令 UUID。

請求結構

CommandUpdateRequest
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command. When False the command stays fully usable over REST but is never loaded as an agent tool.
definitionCommandDefinition-InputTyped inputs and ordered multi-table write steps.
descriptionstringHuman-readable purpose and usage notes.
namestringCommand display name; unique within its scope.
tag_idstringRequired tag from the same custom-table scope. Every referenced table must currently be assigned to this tag.

回應結構

CommandResponse
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command.
chatroom_idstring | nullChatroom scope id
company_idstring | nullCompany scope id
created_atstring (date-time)未指定
created_bystring未指定
definitionCommandDefinition-OutputFull command definition DSL body stored in CustomTableCommand.definition.
department_idstring | nullDepartment scope id
descriptionstring未指定
idstringCommand UUID
is_deletedbooleanSoft-delete marker
lifecycle_redactedbooleanTrue when callback and lifecycle-trigger configuration is omitted because the caller can execute but cannot manage every target table.
namestring未指定
tag_idstring | null未指定
updated_atstring (date-time)未指定

範例

更新指令定義與說明

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222"
  },
  "body": {
    "name": "建立訂單並扣庫存",
    "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。改為一次最多扣 50 件。",
    "agent_enabled": false,
    "tag_id": "33333333-3333-4333-8333-333333333333",
    "definition": {
      "version": 2,
      "inputs": [
        {
          "name": "customer",
          "type": "string",
          "required": true,
          "max_length": 100,
          "description": "客戶名稱"
        },
        {
          "name": "item",
          "type": "string",
          "required": true,
          "max_length": 100,
          "description": "品項名稱"
        },
        {
          "name": "quantity",
          "type": "integer",
          "required": true,
          "description": "出貨數量"
        }
      ],
      "steps": [
        {
          "kind": "select",
          "name": "stock",
          "from": {
            "table": "55555555-5555-4555-8555-555555555555",
            "as": "s"
          },
          "select": {
            "id": "$row.s.id",
            "on_hand": "$row.s.庫存"
          },
          "where": {
            "$and": [
              {
                "$eq": [
                  "$row.s.品項",
                  "$input.item"
                ]
              }
            ]
          },
          "max_rows": 1
        },
        {
          "kind": "let",
          "name": "on_hand",
          "type": "integer",
          "value": {
            "$single": {
              "relation": "$rel.stock",
              "expr": "$item.on_hand"
            }
          }
        },
        {
          "kind": "assert",
          "name": "stock_ok",
          "condition": {
            "$gte": [
              "$var.on_hand",
              "$input.quantity"
            ]
          },
          "message": "庫存不足,無法建立訂單"
        },
        {
          "kind": "insert",
          "name": "order",
          "table": "44444444-4444-4444-8444-444444444444",
          "values": {
            "客戶": "$input.customer",
            "品項": "$input.item",
            "數量": "$input.quantity",
            "狀態": "draft",
            "建立者": "$ctx.user_id"
          },
          "returning": {
            "id": "$new.id"
          }
        },
        {
          "kind": "update",
          "name": "consume",
          "table": "55555555-5555-4555-8555-555555555555",
          "for_each": "$rel.stock",
          "set": {
            "庫存": {
              "$sub": [
                "$item.on_hand",
                "$input.quantity"
              ]
            }
          },
          "match": {
            "id": "$item.id"
          },
          "max_rows": 1,
          "returning": {
            "id": "$new.id"
          }
        }
      ],
      "outputs": {
        "order_id": {
          "value": {
            "$single": {
              "relation": "$rel.order",
              "expr": "$item.id"
            }
          }
        },
        "remaining": {
          "value": {
            "$sub": [
              "$var.on_hand",
              "$input.quantity"
            ]
          }
        }
      }
    }
  }
}
回應200
{
  "id": "22222222-2222-4222-8222-222222222222",
  "name": "建立訂單並扣庫存",
  "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。改為一次最多扣 50 件。",
  "agent_enabled": false,
  "definition": {
    "version": 2,
    "inputs": [
      {
        "name": "customer",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "客戶名稱"
      },
      {
        "name": "item",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "品項名稱"
      },
      {
        "name": "quantity",
        "type": "integer",
        "required": true,
        "description": "出貨數量"
      }
    ],
    "steps": [
      {
        "kind": "select",
        "name": "stock",
        "from": {
          "table": "55555555-5555-4555-8555-555555555555",
          "as": "s"
        },
        "select": {
          "id": "$row.s.id",
          "on_hand": "$row.s.庫存"
        },
        "where": {
          "$and": [
            {
              "$eq": [
                "$row.s.品項",
                "$input.item"
              ]
            }
          ]
        },
        "max_rows": 1
      },
      {
        "kind": "let",
        "name": "on_hand",
        "type": "integer",
        "value": {
          "$single": {
            "relation": "$rel.stock",
            "expr": "$item.on_hand"
          }
        }
      },
      {
        "kind": "assert",
        "name": "stock_ok",
        "condition": {
          "$gte": [
            "$var.on_hand",
            "$input.quantity"
          ]
        },
        "message": "庫存不足,無法建立訂單"
      },
      {
        "kind": "insert",
        "name": "order",
        "table": "44444444-4444-4444-8444-444444444444",
        "values": {
          "客戶": "$input.customer",
          "品項": "$input.item",
          "數量": "$input.quantity",
          "狀態": "draft",
          "建立者": "$ctx.user_id"
        },
        "returning": {
          "id": "$new.id"
        }
      },
      {
        "kind": "update",
        "name": "consume",
        "table": "55555555-5555-4555-8555-555555555555",
        "for_each": "$rel.stock",
        "set": {
          "庫存": {
            "$sub": [
              "$item.on_hand",
              "$input.quantity"
            ]
          }
        },
        "match": {
          "id": "$item.id"
        },
        "max_rows": 1,
        "returning": {
          "id": "$new.id"
        }
      }
    ],
    "outputs": {
      "order_id": {
        "value": {
          "$single": {
            "relation": "$rel.order",
            "expr": "$item.id"
          }
        }
      },
      "remaining": {
        "value": {
          "$sub": [
            "$var.on_hand",
            "$input.quantity"
          ]
        }
      }
    }
  },
  "tag_id": "33333333-3333-4333-8333-333333333333",
  "chatroom_id": "11111111-1111-4111-8111-111111111111",
  "department_id": null,
  "company_id": null,
  "created_by": "77777777-7777-4777-8777-777777777777",
  "created_at": "2026-07-21T02:10:00",
  "updated_at": "2026-07-21T06:40:00",
  "is_deleted": false,
  "lifecycle_redacted": false
}

錯誤

狀態發生條件錯誤本文
404指令不存在於此範圍,或呼叫者無法管理它目前引用的每一張資料表。
{
  "detail": "Command not found"
}
409這支指令仍有執行被暫存待覆核;staged_change_ids 會列出這些暫存變更。
{
  "detail": {
    "error": "pending_staged_executions",
    "staged_change_ids": [
      "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
    ]
  }
}
409此範圍內已有其他活指令使用這個新名稱。刪除的指令不再佔用名字。
{
  "detail": {
    "error": "command_name_conflict",
    "name": "建立訂單並扣庫存"
  }
}
409有資料表觸發器會呼叫這支指令,因此不能在 write 與 query 之間切換執行模式。
{
  "detail": {
    "error": "command_mode_trigger_conflict",
    "command_id": "22222222-2222-4222-8222-222222222222",
    "from_mode": "write",
    "to_mode": "query",
    "message": "this command is invoked by a table trigger; its execution mode cannot be changed while the trigger references it"
  }
}
409有資料表觸發器會呼叫這支指令,因此新定義不得新增對需覆核資料表的引用。
{
  "detail": {
    "error": "approval_trigger_conflict",
    "command_id": "22222222-2222-4222-8222-222222222222",
    "target_table_id": "44444444-4444-4444-8444-444444444444",
    "target_table_name": "訂單",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
    "message": "this command is invoked by a table trigger; it cannot add a reference to a table that requires approval"
  }
}
409兩筆編寫寫入爭用同一個指令範圍,InnoDB 中止了這一筆。交易已回滾,已儲存的定義維持不變——直接重送請求即可。
{
  "detail": "Concurrent write conflict (lock); please retry the request."
}
422新定義中引用的資料表未掛在 tag_id 上。
{
  "detail": {
    "error": "command_tables_outside_tag",
    "tag_id": "33333333-3333-4333-8333-333333333333",
    "table_ids": [
      "55555555-5555-4555-8555-555555555555"
    ]
  }
}
422新的定義編譯後資料表集合是空的。這也是既有零資料表指令無法原地修好的原因——除非新定義引用了資料表,否則 PUT 對新舊定義一視同仁地拒絕。
{
  "detail": {
    "error": "command_references_no_table",
    "message": "a command must reference at least one custom table in this scope"
  }
}
DELETE
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}

刪除指令

用途

將指令軟刪除,並回傳已標記 is_deleted 的資料。

適用時機

確認沒有觸發器引用、也沒有執行仍在等待覆核後,用它下架一支複合動作。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要刪除的指令 UUID。

回應結構

CommandResponse
欄位型別必填說明
agent_enabledbooleanWhether the chatroom agent may see and invoke this command.
chatroom_idstring | nullChatroom scope id
company_idstring | nullCompany scope id
created_atstring (date-time)未指定
created_bystring未指定
definitionCommandDefinition-OutputFull command definition DSL body stored in CustomTableCommand.definition.
department_idstring | nullDepartment scope id
descriptionstring未指定
idstringCommand UUID
is_deletedbooleanSoft-delete marker
lifecycle_redactedbooleanTrue when callback and lifecycle-trigger configuration is omitted because the caller can execute but cannot manage every target table.
namestring未指定
tag_idstring | null未指定
updated_atstring (date-time)未指定

範例

刪除未被引用的指令

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222"
  }
}
回應200
{
  "id": "22222222-2222-4222-8222-222222222222",
  "name": "建立訂單並扣庫存",
  "description": "一次寫入訂單並扣減對應品項庫存;庫存不足時整筆回滾。",
  "agent_enabled": true,
  "definition": {
    "version": 2,
    "inputs": [
      {
        "name": "customer",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "客戶名稱"
      },
      {
        "name": "item",
        "type": "string",
        "required": true,
        "max_length": 100,
        "description": "品項名稱"
      },
      {
        "name": "quantity",
        "type": "integer",
        "required": true,
        "description": "出貨數量"
      }
    ],
    "steps": [
      {
        "kind": "select",
        "name": "stock",
        "from": {
          "table": "55555555-5555-4555-8555-555555555555",
          "as": "s"
        },
        "select": {
          "id": "$row.s.id",
          "on_hand": "$row.s.庫存"
        },
        "where": {
          "$and": [
            {
              "$eq": [
                "$row.s.品項",
                "$input.item"
              ]
            }
          ]
        },
        "max_rows": 1
      },
      {
        "kind": "let",
        "name": "on_hand",
        "type": "integer",
        "value": {
          "$single": {
            "relation": "$rel.stock",
            "expr": "$item.on_hand"
          }
        }
      },
      {
        "kind": "assert",
        "name": "stock_ok",
        "condition": {
          "$gte": [
            "$var.on_hand",
            "$input.quantity"
          ]
        },
        "message": "庫存不足,無法建立訂單"
      },
      {
        "kind": "insert",
        "name": "order",
        "table": "44444444-4444-4444-8444-444444444444",
        "values": {
          "客戶": "$input.customer",
          "品項": "$input.item",
          "數量": "$input.quantity",
          "狀態": "draft",
          "建立者": "$ctx.user_id"
        },
        "returning": {
          "id": "$new.id"
        }
      },
      {
        "kind": "update",
        "name": "consume",
        "table": "55555555-5555-4555-8555-555555555555",
        "for_each": "$rel.stock",
        "set": {
          "庫存": {
            "$sub": [
              "$item.on_hand",
              "$input.quantity"
            ]
          }
        },
        "match": {
          "id": "$item.id"
        },
        "max_rows": 1,
        "returning": {
          "id": "$new.id"
        }
      }
    ],
    "outputs": {
      "order_id": {
        "value": {
          "$single": {
            "relation": "$rel.order",
            "expr": "$item.id"
          }
        }
      },
      "remaining": {
        "value": {
          "$sub": [
            "$var.on_hand",
            "$input.quantity"
          ]
        }
      }
    }
  },
  "tag_id": "33333333-3333-4333-8333-333333333333",
  "chatroom_id": "11111111-1111-4111-8111-111111111111",
  "department_id": null,
  "company_id": null,
  "created_by": "77777777-7777-4777-8777-777777777777",
  "created_at": "2026-07-21T02:10:00",
  "updated_at": "2026-07-21T07:15:00",
  "is_deleted": true,
  "lifecycle_redacted": false
}

錯誤

狀態發生條件錯誤本文
404指令不存在於此範圍,或呼叫者既無法管理它引用的每一張資料表、也不具備指令所屬範圍的權威(聊天室建立者/管理員、部門管理員或公司管理員)。這個範圍權威後備正是資料表被刪或被 purge 之後指令仍刪得掉的原因;兩項檢查都不過的人拿到的就是這顆不可枚舉的 404。
{
  "detail": "Command not found"
}
409這支指令仍有執行被暫存待覆核。
{
  "detail": {
    "error": "pending_staged_executions",
    "staged_change_ids": [
      "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
    ]
  }
}
409仍有資料表觸發器帶著指向這支指令的 invoke_command 動作;references 會列出每張資料表與觸發器。
{
  "detail": {
    "error": "command_referenced_by_trigger",
    "command_id": "22222222-2222-4222-8222-222222222222",
    "references": [
      {
        "table_id": "44444444-4444-4444-8444-444444444444",
        "table_name": "訂單",
        "trigger_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
        "trigger_name": "訂單建立後記錄"
      }
    ]
  }
}
409兩筆編寫寫入爭用同一個指令範圍,InnoDB 中止了這一筆。交易已回滾,指令仍然存在——直接重送請求即可。
{
  "detail": "Concurrent write conflict (lock); please retry the request."
}
POST
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}/execute

執行指令

用途

以綁定的 inputs 執行 write 模式指令,所有步驟一起提交,或一起回滾。

適用時機

真正要做出商業動作時呼叫——下訂單、訂時段、結案——尤其是「只成功一半」會弄髒資料的情況。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}/execute
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}/execute
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}/execute

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要執行的指令 UUID。
dbqueryintRedis 邏輯資料庫編號,因共用 client 相依而外洩到 schema 上。它是內部旋鈕,不屬於指令契約,請不要填。

請求結構

CommandExecuteRequest
欄位型別必填說明
expected_contract_digeststring | nullOptional lowercase 64-hex SHA-256 of the exact current stored command definition. A trusted manual caller may send it when executing against an exact reviewed definition snapshot; omission preserves normal manual execution behavior. Generated agent write-command tools keep the digest server-private and inject their pinned value only after later unambiguous natural-language confirmation. A mismatch fails before input validation, idempotency reservation, audit creation, row locking, or mutation.
idempotency_keystring | nullActor-bucketed idempotency key; failed executions do not block retry.
inputsobjectValues for the command's declared inputs; server context is excluded.

回應結構

CommandExecutionResponse
欄位型別必填說明
authorization_snapshotobject | nullImmutable command scope, tag, and referenced-table audit facts.
command_idstring | null未指定
created_atstring (date-time) | null未指定
duration_msinteger | null未指定
errorstring | null未指定
executed_atstring (date-time) | nullWall-clock stamp frozen at the ORIGINAL execution; an idempotent replay returns the same stamp, so callers can distinguish a replayed earlier result from a fresh write.
execution_idstring未指定
idempotency_keystring | null未指定
input_snapshotobject | null未指定
invoker_client_idstring | null未指定
invoker_idstring | null未指定
outputsobject | nullDeclared version-2 scalar or bounded relation outputs. Internal temporary relations and step rows are never exposed.
response_bodyobject | null未指定
result_refsobject[] | null未指定
staged_change_idstring | null未指定
status"succeeded" | "staged" | "failed"未指定
steps(CommandExecutionV1StepResponse | CommandExecutionV2StepResponse)[]未指定
truncatedboolean | nullTrue when the persisted response snapshot was trimmed to the audit byte cap: declared outputs/step rows are omitted from this body. Set on an idempotent replay of a large execution so the caller can distinguish a trimmed snapshot from a genuinely empty result.

範例

一次完成下訂單與扣庫存

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222"
  },
  "body": {
    "inputs": {
      "customer": "長榮工業",
      "item": "螺絲 M4",
      "quantity": 12
    },
    "idempotency_key": "order-2026-07-21-0042"
  }
}
回應200
{
  "execution_id": "66666666-6666-4666-8666-666666666666",
  "status": "succeeded",
  "steps": [
    {
      "name": "stock",
      "kind": "select",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        },
        "on_hand": {
          "type": "integer",
          "nullable": true
        }
      }
    },
    {
      "name": "on_hand",
      "kind": "let",
      "status": "succeeded",
      "row_count": 0,
      "schema": {}
    },
    {
      "name": "stock_ok",
      "kind": "assert",
      "status": "succeeded",
      "row_count": 0,
      "schema": {}
    },
    {
      "name": "order",
      "kind": "insert",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        }
      }
    },
    {
      "name": "consume",
      "kind": "update",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        }
      }
    }
  ],
  "outputs": {
    "order_id": "88888888-8888-4888-8888-888888888888",
    "remaining": 8
  }
}

錯誤

狀態發生條件錯誤本文
400這次執行展開後會超過 1000 筆 row action 上限;actual 是觸發上限的實際數量。
{
  "detail": {
    "error": "cap_exceeded",
    "cap": 1000,
    "actual": 1240
  }
}
400identity 型別的 input 指向的使用者或社群媒體 client 不屬於此範圍。
{
  "detail": {
    "error": "identity_not_associated",
    "input": "assignee"
  }
}
400版本 1 的 update 或 delete 步驟把選填 input 綁在 match 條件裡,而呼叫者沒有送這個值。現在整次執行失敗,而不是把那個 key 丟掉:丟掉會放寬選列條件,打到建置者從未鎖定的資料列。
{
  "detail": "step 'consume': optional input cannot omit a match key"
}
400被省略的選填 input 出現在 $case 裡——某個分支的 then,或 else。所有分支都必須綁得出值,因為分支要更晚才會對著鎖定的前影像挑選,所以「這個分支綁不出來」只能是錯誤,不能靠猜。
{
  "detail": "step 'order': optional input cannot omit a $case result"
}
403版本 2 程式從呼叫者無法讀取的資料表 select 或 join。過去 row ACL 會把它變成永不匹配的條件,該步驟回傳空 relation,於是「先查再寫」的去重步驟查不到東西,就寫進了一筆重複資料。
{
  "detail": "Read access not granted for this table."
}
403程式有 insert 步驟,而該資料表解析出的 can_insert 是 false。這道檢查與讀取閘門在 `_prepare_program_access` 的同一輪完成——在任何 action core 能 flush 之前——所以不會留下半筆資料。
{
  "detail": "Insert access not granted for this table."
}
403程式有 update 或 delete 步驟,而該資料表解析出的 can_edit 是 "none"。與 insert 同一輪;filtered 或 own 授權在這裡會通過,改在稍後 ACL 範圍內的 match 查詢之後逐列把關。
{
  "detail": "Edit access not granted for this table."
}
403程式要寫入的某張 channel 治理資料表,替你解析不出 scope。REST 不綁 acting room,floor 改為只依執行者逐表解析,因此訊息是「不帶房間」的版本——你名下沒有任何房間在那張表上宣告 scope_values,或候選房間不只一個而無法解析。`table_id` 指出被拒的資料表,`rule_id` 指出讓它進入治理的 channel 規則。
{
  "detail": {
    "error": "scp_scope_undeclared",
    "message": "no chatroom of yours declares a scope on this table",
    "table_id": "55555555-5555-4555-8555-555555555555",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"
  }
}
403寫入 floor 拒絕的是資料列本身:insert 或 update 的受管連結落在你的房間宣告的 scope 之外。同一個 code 也涵蓋前影像檢查(`this record is outside your channel’s scope`,update 打到你的 scope 看不見的列),以及 policy 形式(`this write does not satisfy this table’s channel policy`)。請以 `detail.error` 判別,不要看訊息字串。
{
  "detail": {
    "error": "scp_out_of_scope",
    "message": "this write targets records outside your channel's scope",
    "table_id": "55555555-5555-4555-8555-555555555555",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"
  }
}
403B10 歸因。insert 或 update 的連結值指向一筆確實存在、也通過你的 row ACL 的目標,只有目標資料表的 channel scope 把它藏起來——所以這條通道直接說出 floor 的 code,而不是收斂成統一的 404。在這個分支存在之前,同樣的 v2 寫入會掉進一般性的 500 `command_execution_failed`。當 floor 的判定是那樣時,`scp_scope_undeclared` 與 `scp_rule_dangling` 也會從這裡冒出來;這個形狀沒有 `rule_id`。
{
  "detail": {
    "error": "scp_out_of_scope",
    "message": "link target(s) 88888888-8888-4888-8888-888888888888: the link target exists but is outside your channel scope",
    "table_id": "44444444-4444-4444-8444-444444444444"
  }
}
403連結目標所屬的資料表對你解析出的 `can_read` 是 "none"。這是資料表層級的拒絕,與下面逐列的 404 不同,而且只針對「新增的」目標 id——保留與移除的 id 不受檢查。
{
  "detail": "link target records not found or not accessible"
}
404指令不存在於此範圍、已被軟刪除,或引用了呼叫者無法讀取的資料表。
{
  "detail": "Command not found"
}
404連結值指向的目標不存在、已軟刪除,或被 row ACL 對你藏起來。三種情況共用同一個 body,所以這條路由不會開出 id 列舉的破口。注意:這個 404 與同一路由另一個代表「Command not found」的 404 撞在一起——請讀 detail 字串,不要只看狀態碼。
{
  "detail": "linked record not found"
}
409require_approval 規則觸發,整份計畫被暫存而非提交。寫入是被扣住,不是遺失。
{
  "detail": {
    "error": "approval_required",
    "process_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
    "rule_label": "高金額訂單需主管覆核",
    "staged_change_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
  }
}
409選填的 expected_contract_digest 不符合 command 的即時定義。檢查發生在 command input 驗證、idempotency 保留、建立稽核、row lock 或異動之前,因此沒有資料被改動,也不可原樣重試這份已過期的釘選 request。
{
  "detail": {
    "error": "command_contract_mismatch"
  }
}
409同一位執行者以相同 idempotency key 送出不同的 inputs。
{
  "detail": {
    "error": "idempotency_key_reuse"
  }
}
409另一個持有相同 key 的請求仍在執行中,等它結束後再重試。
{
  "detail": {
    "error": "idempotency_in_progress"
  }
}
409這支指令的 mode 是 "query",必須改用 /query 呼叫。
{
  "detail": {
    "error": "query_command_requires_query_route"
  }
}
409兩次執行爭用同一批資料列,InnoDB 中止了這一次。交易已回滾,沒有任何部分寫入落地,retryable 為 true——請用「同一把」idempotency key 重試:失敗路徑會釋放該 key 的保留,因此重用是合法的。
{
  "detail": {
    "error": "command_lock_conflict",
    "phase": "execute",
    "message": "Concurrent write conflict (lock); please retry the request.",
    "retryable": true,
    "details": {}
  }
}
422宣告的 rule 或 assert 步驟失敗;rule 是規則名稱,message 是建置者自訂的文字。
{
  "detail": {
    "error": "command_rule_failed",
    "rule": "stock_ok",
    "message": "庫存不足,無法建立訂單"
  }
}
503Idempotency 儲存無法連線,為避免重複寫入而直接失敗。
{
  "detail": "Command idempotency service is unavailable"
}
POST
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}/query

執行 query 模式指令

用途

執行唯讀指令,回傳其宣告 relation output 的一頁資料,以及所有 scalar outputs。

適用時機

用於複合讀取——join、彙總、篩選投影——把邏輯寫在伺服器一次,而不是讓前端自己拼。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}/query
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}/query
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}/query

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要執行的 query 模式指令 UUID。

請求結構

CommandQueryRequest
欄位型別必填說明
inputsobjectValues for the command's declared inputs; server context is excluded.
pageCommandQueryPage | nullOptional pagination window; defaults to the first page of 100 rows.

回應結構

CommandQueryResponse
欄位型別必填說明
next_cursorstring | nullOpaque cursor for the next page, or null when exhausted.
outputsobjectDeclared scalar outputs (relation outputs are paginated via rows).
rowsobject[]Projected rows of the paginated relation output for this page.
total_availableinteger | nullTotal rows available in the paginated relation, when known.

範例

讀取篩選後訂單投影的第一頁

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "99999999-9999-4999-8999-999999999999"
  },
  "body": {
    "inputs": {
      "min_quantity": 10
    },
    "page": {
      "output": "result",
      "limit": 2
    }
  }
}
回應200
{
  "rows": [
    {
      "id": "88888888-8888-4888-8888-888888888888",
      "客戶": "長榮工業",
      "數量": 12
    },
    {
      "id": "88888888-8888-4888-8888-222222222222",
      "客戶": "大同機械",
      "數量": 10
    }
  ],
  "outputs": {},
  "next_cursor": "eyJvIjoyLCJkIjoiOWYyYzFhIn0",
  "total_available": 7
}

錯誤

狀態發生條件錯誤本文
400cursor 已無法對應這支指令的 dependency contract、inputs 或 output 名稱,通常是換頁之間 schema 或 inputs 變了。
{
  "detail": {
    "error": "cursor_binding_mismatch"
  }
}
400page.output 指的不是這支指令的 relation output。
{
  "detail": "page.output does not name a relation output"
}
403程式的 select 來源或 join 目標解析出的 can_read 是 none。在這道閘門之前,同樣的呼叫會回 200 加一個空 relation,agent 則回報「查無符合資料」。
{
  "detail": "Read access not granted for this table."
}
404指令不存在於此範圍、已被軟刪除,或引用了呼叫者無法讀取的資料表。
{
  "detail": "Command not found"
}
409這是一支寫入指令,請改用 /execute 呼叫。
{
  "detail": {
    "error": "not_a_query_command"
  }
}
422這一頁序列化後超過 64 KiB 的輸出上限;請調小 page.limit 或縮減 output 的 select 欄位。
{
  "detail": {
    "error": "output_limit_exceeded",
    "phase": "execute",
    "message": "Command output exceeds its byte limit",
    "retryable": false,
    "details": {
      "actual": 71234,
      "limit": 65536,
      "resource": "output_bytes"
    }
  }
}
GET
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}/executions

列出指令的執行紀錄

用途

回傳單一指令的稽核紀錄——inputs、outputs、狀態、耗時,以及執行當下擷取的權限快照,新到舊排序。

適用時機

用來回答「那次到底跑成功了沒、改了什麼」,而不必回頭翻每一張被影響的資料表。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}/executions
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}/executions
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}/executions

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid要查詢執行紀錄的指令 UUID。
skipqueryint >= 0略過前幾筆可見執行紀錄,預設為 0。
limitqueryint 1..200最多回傳幾筆執行紀錄,可填 1 到 200,預設為 50。

回應結構

CommandExecutionListResponse
欄位型別必填說明
itemsCommandExecutionResponse[]未指定
totalinteger未指定

範例

列出某支指令的近期執行紀錄

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222"
  },
  "query": {
    "skip": "0",
    "limit": "20"
  }
}
回應200
{
  "items": [
    {
      "execution_id": "66666666-6666-4666-8666-666666666666",
      "status": "succeeded",
      "steps": [
        {
          "name": "stock",
          "kind": "select",
          "status": "succeeded",
          "row_count": 1,
          "schema": {
            "id": {
              "type": "string",
              "nullable": false
            },
            "on_hand": {
              "type": "integer",
              "nullable": true
            }
          }
        },
        {
          "name": "on_hand",
          "kind": "let",
          "status": "succeeded",
          "row_count": 0,
          "schema": {}
        },
        {
          "name": "stock_ok",
          "kind": "assert",
          "status": "succeeded",
          "row_count": 0,
          "schema": {}
        },
        {
          "name": "order",
          "kind": "insert",
          "status": "succeeded",
          "row_count": 1,
          "schema": {
            "id": {
              "type": "string",
              "nullable": false
            }
          }
        },
        {
          "name": "consume",
          "kind": "update",
          "status": "succeeded",
          "row_count": 1,
          "schema": {
            "id": {
              "type": "string",
              "nullable": false
            }
          }
        }
      ],
      "outputs": {
        "order_id": "88888888-8888-4888-8888-888888888888",
        "remaining": 8
      },
      "command_id": "22222222-2222-4222-8222-222222222222",
      "invoker_id": "77777777-7777-4777-8777-777777777777",
      "idempotency_key": "order-2026-07-21-0042",
      "duration_ms": 84,
      "created_at": "2026-07-21T03:02:11",
      "input_snapshot": {
        "customer": "長榮工業",
        "item": "螺絲 M4",
        "quantity": 12
      },
      "result_refs": [
        {
          "name": "order",
          "table_id": "44444444-4444-4444-8444-444444444444",
          "record_ids": [
            "88888888-8888-4888-8888-888888888888"
          ]
        }
      ],
      "authorization_snapshot": {
        "version": 1,
        "scope": {
          "kind": "chatroom",
          "id": "11111111-1111-4111-8111-111111111111"
        },
        "tag_id": "33333333-3333-4333-8333-333333333333",
        "table_ids": [
          "44444444-4444-4444-8444-444444444444",
          "55555555-5555-4555-8555-555555555555"
        ],
        "command_updated_at": "2026-07-21T02:10:00",
        "audience": "internal",
        "origin": "manual",
        "ai": false,
        "company_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
        "acting_chatroom_id": "11111111-1111-4111-8111-111111111111",
        "department_id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
      }
    }
  ],
  "total": 1
}

錯誤

狀態發生條件錯誤本文
403請求使用 UserAPIKey 而非 JWT 驗證。
{
  "detail": "Custom-table command routes require JWT authentication"
}
404指令不存在於此範圍、已被軟刪除,或引用了呼叫者無法讀取的資料表。
{
  "detail": "Command not found"
}
GET
路由範本/private/module/custom_tables/{scopeWithId}/commands/{command_id}/executions/{execution_id}

取得單筆執行紀錄

用途

回傳一筆執行稽核紀錄,含 input 快照、寫入結果參照、儲存的回應內容與權限快照。

適用時機

收到 409 approval_required 後輪詢它,觀察 staged 紀錄在覆核結束後變成 succeeded 或 failed。

實際掛載路徑
  • 聊天室/private/module/custom_tables/chatroom/{chatroom_id}/commands/{command_id}/executions/{execution_id}
  • 部門/private/module/custom_tables/department/{department_id}/commands/{command_id}/executions/{execution_id}
  • 公司/private/module/custom_tables/company/{company_id}/commands/{command_id}/executions/{execution_id}

範圍

範圍是否提供驗證與權限
聊天室可使用require_jwt_user + ChatRoomJoinedRequired
部門可使用require_jwt_user + DepartmentTenantRequired
公司可使用require_jwt_user + CompanyTenantRequired

參數

欄位位置型別必填說明
command_idpathuuid執行紀錄所屬的指令 UUID。
execution_idpathuuid要讀取的執行紀錄 UUID。

回應結構

CommandExecutionResponse
欄位型別必填說明
authorization_snapshotobject | nullImmutable command scope, tag, and referenced-table audit facts.
command_idstring | null未指定
created_atstring (date-time) | null未指定
duration_msinteger | null未指定
errorstring | null未指定
executed_atstring (date-time) | nullWall-clock stamp frozen at the ORIGINAL execution; an idempotent replay returns the same stamp, so callers can distinguish a replayed earlier result from a fresh write.
execution_idstring未指定
idempotency_keystring | null未指定
input_snapshotobject | null未指定
invoker_client_idstring | null未指定
invoker_idstring | null未指定
outputsobject | nullDeclared version-2 scalar or bounded relation outputs. Internal temporary relations and step rows are never exposed.
response_bodyobject | null未指定
result_refsobject[] | null未指定
staged_change_idstring | null未指定
status"succeeded" | "staged" | "failed"未指定
steps(CommandExecutionV1StepResponse | CommandExecutionV2StepResponse)[]未指定
truncatedboolean | nullTrue when the persisted response snapshot was trimmed to the audit byte cap: declared outputs/step rows are omitted from this body. Set on an idempotent replay of a large execution so the caller can distinguish a trimmed snapshot from a genuinely empty result.

範例

檢視等待覆核中的暫存執行

請求
{
  "pathParams": {
    "chatroom_id": "11111111-1111-4111-8111-111111111111",
    "command_id": "22222222-2222-4222-8222-222222222222",
    "execution_id": "66666666-6666-4666-8666-666666666666"
  }
}
回應200
{
  "execution_id": "66666666-6666-4666-8666-666666666666",
  "status": "staged",
  "steps": [],
  "command_id": "22222222-2222-4222-8222-222222222222",
  "invoker_id": "77777777-7777-4777-8777-777777777777",
  "idempotency_key": "order-2026-07-21-0043",
  "staged_change_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
  "duration_ms": 119,
  "created_at": "2026-07-21T05:44:02",
  "input_snapshot": {
    "customer": "大同機械",
    "item": "螺絲 M4",
    "quantity": 400
  },
  "response_body": {
    "error": "approval_required",
    "process_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
    "rule_label": "高金額訂單需主管覆核",
    "staged_change_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
  },
  "authorization_snapshot": {
    "version": 1,
    "scope": {
      "kind": "chatroom",
      "id": "11111111-1111-4111-8111-111111111111"
    },
    "tag_id": "33333333-3333-4333-8333-333333333333",
    "table_ids": [
      "44444444-4444-4444-8444-444444444444",
      "55555555-5555-4555-8555-555555555555"
    ],
    "command_updated_at": "2026-07-21T02:10:00",
    "audience": "internal",
    "origin": "manual",
    "ai": false,
    "company_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "acting_chatroom_id": "11111111-1111-4111-8111-111111111111",
    "department_id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
  }
}

錯誤

狀態發生條件錯誤本文
404指令不存在於此範圍,或呼叫者無法讀取它引用的每一張資料表。
{
  "detail": "Command not found"
}
404該指令下沒有這個 id 的執行紀錄,或呼叫者看不到它。
{
  "detail": "Command execution not found"
}
POST
路由範本/private/module/custom_tables/agent/commands/{command_id}/execute

以 agent 身分執行指令

用途

在可信的服務通道上執行指令;身分來自伺服器注入的 header,而不是路徑上的範圍區段。

適用時機

當 agent runtime 的模型工具需要代表特定「使用者+聊天室」或社群媒體 client 執行複合寫入時使用。

實際掛載路徑
  • 完整路由/private/module/custom_tables/agent/commands/{command_id}/execute

範圍

範圍是否提供驗證與權限
完整路由可使用resolve_command_service_principal (X-API-Key service token)

參數

欄位位置型別必填說明
command_idpathuuid要執行的指令 UUID;其範圍由綁定的 principal 推導。
dbqueryintRedis 邏輯資料庫編號,因共用 client 相依而外洩到 schema 上,請不要填。

請求結構

CommandExecuteRequest
欄位型別必填說明
expected_contract_digeststring | nullOptional lowercase 64-hex SHA-256 of the exact current stored command definition. A trusted manual caller may send it when executing against an exact reviewed definition snapshot; omission preserves normal manual execution behavior. Generated agent write-command tools keep the digest server-private and inject their pinned value only after later unambiguous natural-language confirmation. A mismatch fails before input validation, idempotency reservation, audit creation, row locking, or mutation.
idempotency_keystring | nullActor-bucketed idempotency key; failed executions do not block retry.
inputsobjectValues for the command's declared inputs; server context is excluded.

回應結構

CommandExecutionResponse
欄位型別必填說明
authorization_snapshotobject | nullImmutable command scope, tag, and referenced-table audit facts.
command_idstring | null未指定
created_atstring (date-time) | null未指定
duration_msinteger | null未指定
errorstring | null未指定
executed_atstring (date-time) | nullWall-clock stamp frozen at the ORIGINAL execution; an idempotent replay returns the same stamp, so callers can distinguish a replayed earlier result from a fresh write.
execution_idstring未指定
idempotency_keystring | null未指定
input_snapshotobject | null未指定
invoker_client_idstring | null未指定
invoker_idstring | null未指定
outputsobject | nullDeclared version-2 scalar or bounded relation outputs. Internal temporary relations and step rows are never exposed.
response_bodyobject | null未指定
result_refsobject[] | null未指定
staged_change_idstring | null未指定
status"succeeded" | "staged" | "failed"未指定
steps(CommandExecutionV1StepResponse | CommandExecutionV2StepResponse)[]未指定
truncatedboolean | nullTrue when the persisted response snapshot was trimmed to the audit byte cap: declared outputs/step rows are omitted from this body. Set on an idempotent replay of a large execution so the caller can distinguish a trimmed snapshot from a genuinely empty result.

範例

從 agent runtime 執行訂單指令

請求
{
  "pathParams": {
    "command_id": "22222222-2222-4222-8222-222222222222"
  },
  "body": {
    "inputs": {
      "customer": "長榮工業",
      "item": "螺絲 M4",
      "quantity": 12
    },
    "idempotency_key": "agent-run-9f2c1a"
  }
}
回應200
{
  "execution_id": "66666666-6666-4666-8666-666666666666",
  "status": "succeeded",
  "steps": [
    {
      "name": "stock",
      "kind": "select",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        },
        "on_hand": {
          "type": "integer",
          "nullable": true
        }
      }
    },
    {
      "name": "on_hand",
      "kind": "let",
      "status": "succeeded",
      "row_count": 0,
      "schema": {}
    },
    {
      "name": "stock_ok",
      "kind": "assert",
      "status": "succeeded",
      "row_count": 0,
      "schema": {}
    },
    {
      "name": "order",
      "kind": "insert",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        }
      }
    },
    {
      "name": "consume",
      "kind": "update",
      "status": "succeeded",
      "row_count": 1,
      "schema": {
        "id": {
          "type": "string",
          "nullable": false
        }
      }
    }
  ],
  "outputs": {
    "order_id": "88888888-8888-4888-8888-888888888888",
    "remaining": 8
  }
}

錯誤

狀態發生條件錯誤本文
400header 既沒有完整的 user + chatroom 組合,也沒有單獨的社群媒體 client id,或兩種形式混用。
{
  "detail": "Provide exactly user+chatroom or social-media-client identity"
}
400具型別的 channel headers 組合無效。X-TeamSync-Agent-Group-Scope 只在 line_group 與 line_room 時必填,其他 channel 一律不得出現。
{
  "detail": {
    "error": "invalid_agent_group_scope"
  }
}
401X-API-Key 與伺服器設定的指令服務 token 不符。
{
  "detail": "Invalid command service credential"
}
403指定的身分不存在、已停用,或不屬於它宣稱的聊天室或租戶。
{
  "detail": "Command principal is not authorized"
}
403程式讀取了 acting room 未授予讀取權的資料表。這條通道的部門資料表權限釘在 acting room 上,執行者其他聊天室給的授權在這裡不算數。
{
  "detail": "Read access not granted for this table."
}
403insert 步驟打到 acting room 未授予 insert 權的資料表。與讀取 403 是同一道前置閘門,所以不會寫入任何資料。
{
  "detail": "Insert access not granted for this table."
}
403update 或 delete 步驟打到的資料表,在 acting room 下 `can_edit` 解析為 "none"。filtered 或 own 授權會通過這裡,改在稍後逐列把關。
{
  "detail": "Edit access not granted for this table."
}
403acting room 在程式要寫入的某張 channel 治理資料表上沒有宣告 scope_values。這條通道釘住房間,所以訊息會把房間點名——不綁房間的 REST 對應版本,同一個 code 會說 `no chatroom of yours declares a scope on this table`。
{
  "detail": {
    "error": "scp_scope_undeclared",
    "message": "chatroom 11111111-1111-4111-8111-111111111111 has no declared scope on this table",
    "table_id": "55555555-5555-4555-8555-555555555555",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"
  }
}
403寫入 floor 拒絕了這筆資料列:acting room 宣告的 scope 涵蓋不到該步驟要寫的紀錄或它要設的連結。這是終局性的政策拒絕——從同一個房間重試不可能成功,agent protocol 也要求把訊息轉達給使用者後停手,不要繞路。
{
  "detail": {
    "error": "scp_out_of_scope",
    "message": "this write targets records outside your channel's scope",
    "table_id": "55555555-5555-4555-8555-555555555555",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"
  }
}
403連結值指向的目標確實存在、也通過 ACL,只有目標資料表的 channel scope 對 acting room 把它藏起來。與 REST 通道相同的 B10 歸因;在它之前,這個情況會回 500 `command_execution_failed`。
{
  "detail": {
    "error": "scp_out_of_scope",
    "message": "link target(s) 88888888-8888-4888-8888-888888888888: the link target exists but is outside your channel scope",
    "table_id": "44444444-4444-4444-8444-444444444444"
  }
}
403連結目標所屬資料表在 acting room 下解析出的 `can_read` 是 "none"。只針對新增的目標 id。
{
  "detail": "link target records not found or not accessible"
}
404從綁定 principal 的聊天室、部門或公司都看不到這個 id 的指令。
{
  "detail": "Command not found"
}
404指令存在、範圍也看得到,但 agent_enabled 是 false。回應內容與「id 不存在」完全相同,所以 agent 通道不會洩漏任何存在性訊號。
{
  "detail": "Command not found"
}
404連結目標不存在、已軟刪除,或被 row ACL 藏起來——三種情況共用同一個 body。與上面的 Command not found 404 不同,請讀 detail 字串。
{
  "detail": "linked record not found"
}
409同一位 principal 以相同 idempotency key 送出不同的 inputs。
{
  "detail": {
    "error": "idempotency_key_reuse"
  }
}
409require_approval 規則觸發,計畫已被暫存待覆核。
{
  "detail": {
    "error": "approval_required",
    "process_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
    "rule_id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
    "rule_label": "高金額訂單需主管覆核",
    "staged_change_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
  }
}
409Write 模式 command 的定義,在伺服器完成不寫入的準備後、依使用者後續自然語言同意執行前發生變更。Adapter 呼叫在保留、稽核、加鎖或異動前就被拒絕;請丟棄過期的準備狀態並再次詢問使用者。
{
  "detail": {
    "error": "command_contract_mismatch"
  }
}
409兩次執行爭用同一批資料列,InnoDB 中止了這一次。交易已回滾,沒有任何部分寫入落地,retryable 為 true——請用「同一把」idempotency key 重試:失敗路徑會釋放該 key 的保留,因此重用是合法的。
{
  "detail": {
    "error": "command_lock_conflict",
    "phase": "execute",
    "message": "Concurrent write conflict (lock); please retry the request.",
    "retryable": true,
    "details": {}
  }
}
422必要的具型別 header 缺漏或格式錯誤。X-TeamSync-Agent-Channel 必須是 ChatChannelType 值;X-TeamSync-Agent-Group-Scope 一旦出現,就必須恰好是 64 個小寫十六進位字元。這些 shape 錯誤會先由 request validation 拒絕,之後才輪到 400 的組合檢查。
{
  "detail": [
    {
      "type": "missing",
      "loc": [
        "header",
        "X-TeamSync-Agent-Channel"
      ],
      "msg": "Field required",
      "input": null
    }
  ]
}
503伺服器未設定 CUSTOM_TABLE_COMMAND_SERVICE_TOKEN。
{
  "detail": "Custom-table command service is not configured"
}
POST
路由範本/private/module/custom_tables/agent/commands/{command_id}/query

以 agent 身分執行 query 模式指令

用途

在可信的服務通道上執行唯讀指令,回傳一頁投影後的分頁資料。

適用時機

用於只讀取的 agent 工具——查詢、彙總、篩選清單——讓模型完全碰不到寫入通道。

實際掛載路徑
  • 完整路由/private/module/custom_tables/agent/commands/{command_id}/query

範圍

範圍是否提供驗證與權限
完整路由可使用resolve_command_service_principal (X-API-Key service token)

參數

欄位位置型別必填說明
command_idpathuuid要執行的 query 模式指令 UUID;其範圍由綁定的 principal 推導。

請求結構

CommandQueryRequest
欄位型別必填說明
inputsobjectValues for the command's declared inputs; server context is excluded.
pageCommandQueryPage | nullOptional pagination window; defaults to the first page of 100 rows.

回應結構

CommandQueryResponse
欄位型別必填說明
next_cursorstring | nullOpaque cursor for the next page, or null when exhausted.
outputsobjectDeclared scalar outputs (relation outputs are paginated via rows).
rowsobject[]Projected rows of the paginated relation output for this page.
total_availableinteger | nullTotal rows available in the paginated relation, when known.

範例

從 agent runtime 取得投影的下一頁

請求
{
  "pathParams": {
    "command_id": "99999999-9999-4999-8999-999999999999"
  },
  "body": {
    "inputs": {
      "min_quantity": 10
    },
    "page": {
      "output": "result",
      "limit": 2,
      "cursor": "eyJvIjoyLCJkIjoiOWYyYzFhIn0"
    }
  }
}
回應200
{
  "rows": [
    {
      "id": "88888888-8888-4888-8888-333333333333",
      "客戶": "中鋼結構",
      "數量": 10
    }
  ],
  "outputs": {},
  "next_cursor": null,
  "total_available": 7
}

錯誤

狀態發生條件錯誤本文
400header 既沒有完整的 user + chatroom 組合,也沒有單獨的社群媒體 client id,或兩種形式混用。
{
  "detail": "Provide exactly user+chatroom or social-media-client identity"
}
401X-API-Key 與伺服器設定的指令服務 token 不符。
{
  "detail": "Invalid command service credential"
}
403指定的身分不存在、已停用,或不屬於它宣稱的聊天室或租戶。
{
  "detail": "Command principal is not authorized"
}
403select 來源或 join 目標在 acting room 的授權下解析出 can_read 為 none,因此呼叫大聲失敗,而不是回一頁空資料讓模型讀成「什麼都沒有」。
{
  "detail": "Read access not granted for this table."
}
404從綁定 principal 的聊天室、部門或公司都看不到這個 id 的指令。
{
  "detail": "Command not found"
}
409這是一支寫入指令,必須改走 agent 的 execute 路由。
{
  "detail": {
    "error": "not_a_query_command"
  }
}
Last updated on