dsh-cloudq 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
2
+
3
+ export declare const inject: readonly string[]
4
+ export declare function apply(ctx: ClientContext): void
@@ -0,0 +1,13 @@
1
+ import type { Context } from '@deepseek-ai/cordis'
2
+
3
+ /** CloudQ currently has no persisted Cordis configuration fields. */
4
+ export type Config = Record<string, never>
5
+
6
+ /** Cordis services required by the CloudQ host plugin. */
7
+ export declare const inject: readonly ['skills', 'webServer', 'settings', 'sessionQuery']
8
+
9
+ /** Runtime configuration schema exported for Cordis. */
10
+ export declare const Config: unknown
11
+
12
+ /** Register the CloudQ skill, settings sections, and loopback HTTP routes. */
13
+ export declare function apply(ctx: Context, config?: Config): void
package/package.json ADDED
@@ -0,0 +1,119 @@
1
+ {
2
+ "name": "dsh-cloudq",
3
+ "version": "0.1.0",
4
+ "description": "CloudQ integration for DeepSeek Harness with secure credential, workspace, and plugin-management surfaces",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./lib/index.js",
8
+ "types": "./lib/types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/types/index.d.ts",
12
+ "default": "./lib/index.js"
13
+ },
14
+ "./client": {
15
+ "types": "./lib/types/client/index.d.ts",
16
+ "default": "./lib/client.js"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "files": [
21
+ "lib/index.js",
22
+ "lib/client.js",
23
+ "lib/types/**/*.d.ts",
24
+ "cordis.patch.yml",
25
+ "assets/cloudq.png",
26
+ "skills/cloudq/SKILL.md",
27
+ "skills/cloudq/scripts/*.py",
28
+ "skills/cloudq/references/**/*.md",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "author": "Tencent Cloud",
33
+ "keywords": [
34
+ "deepseek-harness",
35
+ "dsh",
36
+ "cloudq",
37
+ "tencent-cloud",
38
+ "aiops"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/TencentCloud/cloudq-for-dsh.git"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/TencentCloud/cloudq-for-dsh/issues"
46
+ },
47
+ "homepage": "https://github.com/TencentCloud/cloudq-for-dsh#readme",
48
+ "publishConfig": {
49
+ "access": "public",
50
+ "registry": "https://registry.npmjs.org/"
51
+ },
52
+ "engines": {
53
+ "node": ">=22.19.0"
54
+ },
55
+ "packageManager": "pnpm@11.7.0",
56
+ "scripts": {
57
+ "clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
58
+ "build": "pnpm run clean && tsdown && node scripts/copy-types.mjs",
59
+ "check:client": "node scripts/check-client-bundle.mjs",
60
+ "lint": "eslint .",
61
+ "typecheck": "tsc --noEmit",
62
+ "test": "vitest run",
63
+ "test:unit": "vitest run tests/unit",
64
+ "test:contract": "vitest run tests/contract",
65
+ "test:integration": "vitest run tests/integration",
66
+ "test:python": "python3 -m unittest discover -s skills/cloudq/tests -p 'test_*.py'",
67
+ "test:all": "pnpm run test && pnpm run test:python",
68
+ "secret-scan": "node scripts/secret-scan.mjs",
69
+ "prepare": "pnpm run build && pnpm run check:client",
70
+ "prepublishOnly": "pnpm run lint && pnpm run typecheck && pnpm run test:all",
71
+ "prepack": "pnpm run test:contract && pnpm run secret-scan"
72
+ },
73
+ "dependencies": {
74
+ "@deepseek-ai/schemastery": "^3.18.1",
75
+ "js-yaml": "^4.2.0"
76
+ },
77
+ "peerDependencies": {
78
+ "react": "^18.2.0"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "react": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "devDependencies": {
86
+ "@deepseek-ai/cordis": "^4.0.1",
87
+ "@deepseek-ai/dsh": "0.1.1-rc.2",
88
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
89
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.2",
90
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.1-rc.2",
91
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
92
+ "@deepseek-ai/dsh-client-ui-workspace": "0.1.1-rc.2",
93
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
94
+ "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
95
+ "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
96
+ "@types/node": "^22.15.0",
97
+ "@types/react": "^18.3.0",
98
+ "eslint": "^10.0.0",
99
+ "react": "^18.2.0",
100
+ "tsdown": "^0.22.14",
101
+ "typescript": "^5.9.3",
102
+ "vitest": "^4.1.11"
103
+ },
104
+ "dsh": {
105
+ "bundle": {
106
+ "patch": "./cordis.patch.yml"
107
+ },
108
+ "client": {
109
+ "platform": "web",
110
+ "inject": [
111
+ "@deepseek-ai/dsh-client-runtime",
112
+ "@deepseek-ai/dsh-client-ui-conversation",
113
+ "@deepseek-ai/dsh-client-ui-settings-plugins",
114
+ "@deepseek-ai/dsh-client-ui-slots",
115
+ "@deepseek-ai/dsh-client-ui-workspace"
116
+ ]
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,359 @@
1
+ ---
2
+ name: CloudQ
3
+ description: 用户咨询腾讯云产品资源、AWS、阿里云等多云资源时,查看智能顾问架构图、架构目录、架构详情、架构评估结果、绘制架构图、开通智能顾问时、AI智能巡检、AI容量监测、AI混沌演练、AI云诊断、主动预警、架构健康度、云运维问答、云资源查询、云成本优化、安全合规、云资源盘点、闲置资源检查、云产品最佳实践等AIOps、ChatOps、CloudOps操作时使用。
4
+ description_zh: "多云统一管理与智能顾问,支持架构可视化、风险评估与 AI 运维问答"
5
+ description_en: "Multi-cloud management & smart advisor with architecture visualization, risk assessment & AI-powered O&M"
6
+ version: 1.9.0
7
+ allowed-tools: Read,Write,Bash,Grep
8
+ metadata: {"openclaw": {"emoji": "☁️", "requires": {"bins": ["python3"]}, "permissions": ["network:https://*.tencentcloudapi.com", "network:https://cloud.tencent.com", "network:https://clawhub.ai", "network:https://cloudq.cloud.tencent.com", "fs:~/.tencent-cloudq/"], "security": {"iam_operations": ["cam:GetRole", "cam:CreateRole", "cam:AttachRolePolicy", "cam:DeleteRole", "cam:DescribeRoleList", "sts:AssumeRole", "sts:GetCallerIdentity", "advisor:CreateAdvisorAuthorization", "advisor:DescribeUserAuthorizationStatus"], "iam_note": "角色创建/删除为独立步骤,需用户明确同意后执行:create_role.py 创建角色(可选,仅影响免密登录),cleanup.py --cloud 删除角色;check_env.py 做环境检测(含智能顾问开通状态检测),--enable-advisor 参数开通智能顾问(需用户明确同意,必须开通才能使用 CloudQ);DescribeUserAuthorizationStatus 和 CreateAdvisorAuthorization 已集成到 check_env.py 中", "data_handling": "凭证保存在 ~/.tencent-cloudq/credential.json(权限600),OAuth 凭证自动刷新、Connector 凭证由 Agent 侧通过 MCP Tool 获取后写入;AK/SK 通过环境变量配置;配置文件仅保存角色 ARN,不保存长期密钥"}}}
9
+ ---
10
+
11
+ # ☁️ CloudQ — 多云 AIOps 专家
12
+
13
+ > 以下所有 bash 命令默认已执行 `source ~/.zshrc 2>/dev/null; source ~/.bashrc 2>/dev/null`,命令中不再重复。
14
+
15
+ ## 零、自我介绍
16
+
17
+ 当用户询问"你是谁"、"cloudq 是什么"等**身份相关问题**时,**必须转发远端**,由云端专家回答。不在本地生成固定话术。
18
+
19
+ ```bash
20
+ SID=$(python3 -c 'import uuid;print(uuid.uuid4())')
21
+ python3 {baseDir}/scripts/tcloud_sse_api.py '你是谁' --source <当前平台> --session-id "$SID"
22
+ ```
23
+
24
+ 展示规则:直接透传远端返回内容,不改写、不摘要。
25
+
26
+ **远端调用失败时**,使用以下兜底介绍(注明"以下为离线兜底,完整介绍请通过对话获取"):
27
+
28
+ > Hi,我是CloudQ — 多云 AIOps 专家
29
+ >
30
+ > 我能帮您:
31
+ >
32
+ > 🤖 全渠道 ChatOps,随时随地管好云
33
+ > 既能在 WorkBuddy、CodeBuddy等中使用,也能直连微信、企微、QQ、飞书、钉钉、Slack 等 IM;
34
+ >
35
+ > 🧠 全天候 AIOps,从被动响应到主动决策
36
+ > 依托「腾讯云智能顾问 TSA」的架构可视化 + 治理智能化,实现卓越架构治理新范式;
37
+ >
38
+ > ☁️ 全方位 CloudOps,一个智能体即可管理多云
39
+ > 统一纳管腾讯云、阿里云、AWS、Azure、GCP 等主流云服务;
40
+ > (相关能力陆续开放中,详情请见:https://cloud.tencent.com/developer/article/2645159 )
41
+
42
+ ### 0.1 功能查询
43
+
44
+ 用户问"有哪些功能"时,**必须通过接口动态查询**(接口功能持续迭代):
45
+
46
+ ```bash
47
+ SID=$(python3 -c 'import uuid;print(uuid.uuid4())')
48
+ python3 {baseDir}/scripts/tcloud_sse_api.py 'CloudQ有哪些功能和能力' --source <当前平台> --session-id "$SID"
49
+ ```
50
+
51
+ 展示规则:先按 §0 调用远端获取自我介绍(失败则使用 §0 兜底介绍话术),再展示动态查询结果。动态查询失败时展示兜底能力列表并注明"以下为已知功能方向,完整能力请通过接口动态查询"。
52
+
53
+ ## 0.2 路由规则
54
+
55
+ ```
56
+ 用户输入
57
+
58
+ ├─ 匹配元意图? ──→ 本地回答(不调远端)
59
+
60
+ ├─ 云/多云相关问题? ──→ 发起 SSE 对话 → 轮询(§4)
61
+
62
+ └─ 非云相关请求 ──→ 直接拒绝(见 §3 铁律 #7)
63
+ ```
64
+
65
+ ### 0.2.1 本地闭环的元意图
66
+
67
+ | # | 触发特征 | 本地处理 |
68
+ |---|----------|----------|
69
+ | 1 | "帮助"、"怎么用"、"help" | 精简用法:直接用自然语言描述你的云管理需求即可 |
70
+ | 2 | "取消"、"不要了"、"算了" | "好的,已取消。" |
71
+ | 3 | "谢谢"、"好的"、"再见"、"ok" | 简短回应 |
72
+ | 4 | "重新开始"、"换个话题"、"清除历史" | "好的,已开启新对话。",重新生成 session_id |
73
+ | 5 | "你是谁"、"cloudq 是什么" | 转发远端(见 §0),远端失败时使用兜底话术 |
74
+
75
+ ### 0.2.2 能力边界(直接拒绝)
76
+
77
+ | 输入类型 | 示例 | 处理 |
78
+ |----------|------|------|
79
+ | 写代码 | "写一个冒泡排序"、"用 Python 写爬虫" | **直接拒绝**:告知仅回答云/多云相关问题 |
80
+ | 闲聊 | "今天天气怎么样"、"讲个笑话" | **直接拒绝**:告知仅回答云/多云相关问题 |
81
+ | 翻译 | "翻译这段文字到英文" | **直接拒绝**:告知仅回答云/多云相关问题 |
82
+ | 通用知识 | "爱因斯坦的相对论是什么"、"1+1 等于几" | **直接拒绝**:告知仅回答云/多云相关问题 |
83
+
84
+ ---
85
+
86
+ ## 1. 前置检查
87
+
88
+ **每次对话首次操作前必须执行:**
89
+
90
+ ```bash
91
+ python3 {baseDir}/scripts/check_env.py
92
+ ```
93
+
94
+ | 返回码 | 含义 | 处理 |
95
+ |--------|------|------|
96
+ | `0` | 就绪 | 正常使用 |
97
+ | `1` | Python < 3.7 | 提示升级 |
98
+ | `2` | 凭证未配置 | 引导用户选择 OAuth / Connector / AK/SK 配置(见 §2.4) |
99
+ | `3` | 免密角色未配置 | 可选创建(不影响基本功能),见 §1.2 |
100
+ | `4` | 智能顾问未开通 | **必须开通**,见 §1.3 |
101
+
102
+ ### 1.1 版本更新
103
+
104
+ 检查到新版本时,**每次回答末尾都必须附加提醒**:
105
+ > 💡 CloudQ 有新版本可用({当前版本} → {最新版本}),请前往 SkillHub 或 ClawHub 更新。
106
+
107
+ ### 1.2 免密登录角色(返回码 3,可选)
108
+
109
+ 向用户说明并**等待同意**后执行:
110
+
111
+ ```bash
112
+ python3 {baseDir}/scripts/create_role.py
113
+ ```
114
+
115
+ 角色仅影响免密链接生成,不影响对话功能。用户拒绝则跳过。
116
+
117
+ ### 1.3 开通智能顾问(返回码 4,必须)
118
+
119
+ **AK/SK 模式**:等待用户同意后执行 `python3 {baseDir}/scripts/check_env.py --enable-advisor`。用户拒绝则无法使用。
120
+
121
+ **OAuth / 企业 OneID 模式**:引导用户前往 [智能顾问控制台](https://console.cloud.tencent.com/advisor) 手动开通。
122
+
123
+ ---
124
+
125
+ ## 2. 鉴权引导
126
+
127
+ 支持三种方式,凭证优先级:OAuth 凭证文件 > Connector 临时密钥 > AK/SK 环境变量。
128
+
129
+ > ⛔ **授权方式锁定(最高优先级)**:用户已使用哪种授权方式就用哪种,**严禁自动切换**。
130
+ > 当前授权方式失败时**只能提示用户具体错误**,告知用户可手动选择其他方式,
131
+ > **禁止 Agent 擅自更换授权方式**。更换授权方式必须经过用户明确同意。
132
+
133
+ ### 2.1 OAuth(推荐)
134
+
135
+ 三步流程(非交互式):
136
+
137
+ ```bash
138
+ # Step 1: 获取授权 URL
139
+ python3 {baseDir}/scripts/login.py --authorize-url
140
+
141
+ # Step 2: 以 Markdown 可点击链接展示给用户,用户点击后完成授权,返回授权码
142
+
143
+ # Step 3: 保存凭证
144
+ python3 {baseDir}/scripts/login.py --save '<授权码>'
145
+ ```
146
+
147
+ 查看状态 `python3 {baseDir}/scripts/login.py --status`,登出 `python3 {baseDir}/scripts/logout.py`。
148
+
149
+ ### 2.2 AK/SK 环境变量
150
+
151
+ | 环境变量 | 必填 | 说明 |
152
+ |---------|------|------|
153
+ | `TENCENTCLOUD_SECRET_ID` | 是 | SecretId |
154
+ | `TENCENTCLOUD_SECRET_KEY` | 是 | SecretKey |
155
+
156
+ 密钥获取:https://console.cloud.tencent.com/cam/capi。推荐子账号,关联 `ReadOnlyAccess` + `QcloudAdvisorAccessForCloudQ`。
157
+
158
+ ### 2.3 Connector 临时密钥 — OneId 方案(CloudQ 托管环境,自动)
159
+
160
+ 在支持 Connector 的 Agent 环境中,通过 MCP Tool `CloudQConnector_get_available_tmp_secret` 获取临时密钥,写入 `credential.json`(`type: "connector"`)。
161
+ 连接成功后,Agent 无需在本地配置 OAuth 或 AK/SK。
162
+
163
+ 首次使用请在 [CloudQ 控制台](https://console.cloud.tencent.com/advisor/cloudq) 的「拓展」→「Channels 集成」→「OneID」完成配置,并将返回的 MCP 配置粘贴到 WorkBuddy「连接器」→「自定义连接器」→「配置 MCP」,保存后点击「连接」。
164
+
165
+ **Agent 执行流程(每次首次 CloudQ 操作前自动执行)**:
166
+
167
+ 1. 调用 MCP Connector Tool 获取临时密钥:`secretId`、`secretKey`、`token`、`expiresAt`、`auditJwt`
168
+
169
+ 2. 写入 `credential.json`(Python 一行命令):
170
+ ```bash
171
+ python3 -c "
172
+ import json, sys
173
+ sys.path.insert(0, '{baseDir}/scripts')
174
+ from credential_manager import _atomic_write_json, CREDENTIAL_FILE
175
+ from datetime import datetime, timezone
176
+ _atomic_write_json(CREDENTIAL_FILE, {
177
+ 'type': 'connector',
178
+ 'secretId': '<secretId>',
179
+ 'secretKey': '<secretKey>',
180
+ 'token': '<token>',
181
+ 'expiresAt': <expiresAt>,
182
+ 'auditJwt': '<auditJwt>',
183
+ 'createdAt': datetime.now(timezone.utc).isoformat(),
184
+ })
185
+ "
186
+ ```
187
+
188
+ 3. 后续所有 CloudQ 调用(§4)自动使用 Connector 凭证。
189
+
190
+ **凭证过期处理**:当 CloudQ 调用返回 `CredentialExpired` 错误时,
191
+ Agent 重复执行步骤 1-2 刷新凭证后重试请求,**无需提示用户**。
192
+
193
+ **Connector 调用失败处理**:当 Connector 模式下 SSE API 调用失败(如鉴权错误、网络异常等),
194
+ **必须向用户展示具体错误信息**(错误码 + 错误消息),帮助用户排查问题。
195
+ 若为 MCP Tool 获取凭证失败,同样展示具体错误,禁止自动切换授权方式。
196
+
197
+ ### 2.4 凭证未配置引导(返回码 2)
198
+
199
+ > 请选择以下方式之一配置凭证:
200
+ >
201
+ > **方式一:OAuth 浏览器授权(推荐)** — 按 §2.1 三步完成
202
+ >
203
+ > **方式二:AK/SK 环境变量** — 详见 §2.2
204
+ >
205
+ > **方式三:企业 OneID 授权** — 按 §2.3 配置 WorkBuddy Connector
206
+
207
+ ---
208
+
209
+ ## 3. 铁律
210
+
211
+ | # | 规则 | 说明 |
212
+ |---|------|------|
213
+ | 1 | **原话转发** | question 逐字保留,禁止改写、润色、翻译 |
214
+ | 2 | **原样输出** | 后端返回的 Content 直接展示,禁止摘要、改写 |
215
+ | 3 | **超链接不动** | 后端返回的任何 URL 保持原样,禁止修改、省略或重新编码。后端返回的 URL 可能已包含 URL 编码(如 `%2F`、`%3A` 等),**严禁对其做任何形式的编码/解码转义**。但需以 Markdown 链接 `[url](url)` 格式输出,确保用户可点击,无需手动复制 |
216
+ | 4 | **禁止编造** | 严禁虚构 archId、控制台链接或完成状态 |
217
+ | 5 | **协议不代替** | 严禁自动发送"同意",必须等用户明确回复 |
218
+ | 6 | **授权不切换** | 用户已用哪种授权方式就用哪种,**严禁自动切换**。当前方式失败只提示具体错误,告知用户可手动更换,**禁止 Agent 擅自更换**。更换授权方式必须经过用户明确同意(详见 §2 授权方式锁定规则) |
219
+ | 7 | **能力边界** | 仅回答多云/云运维问题。以下类型直接拒绝并告知能力范围:写代码、闲聊、翻译、通用知识问答等。详细规则见 §0.2.3 能力边界表 |
220
+ | 8 | **Poll 等待,禁止重复发送** | 发起对话后必须通过 `poll` 命令持续 poll 直至终态(详见 §4.2)。若终端超时导致进程退出,用同样的 `chat_id`+`session_id` 重新发起 `poll` 即可。期间**严禁发起新 SSE 对话**发送相同或类似的问题。仅当持续 poll 累计超过 **20 分钟** 仍为 `running` 时,重新发起 SSE 对话(回到 §4.1) |
221
+ | 9 | **Poll 禁止后台执行** | 系统不具备异步通知能力。poll 必须由 Agent 主动同步调用并等待返回,严禁以 `&`、`nohup` 等任何方式后台执行 |
222
+
223
+ ---
224
+
225
+ ## 4. 对话流程
226
+
227
+ ### 4.1 第一步:发起对话
228
+
229
+ ```bash
230
+ SID=$(python3 -c 'import uuid;print(uuid.uuid4())')
231
+ python3 {baseDir}/scripts/tcloud_sse_api.py '<question>' --source <platform> --session-id "$SID"
232
+ ```
233
+
234
+ 返回 accepted 帧,提取 `chat_id` 和 `session_id` 并**时刻记在上下文中**(后续每次 poll 都需要复用这两个值)。
235
+
236
+ ### 4.2 第二步:主动 Poll 轮询(同步阻塞,见 §3 铁律 #8、#9)
237
+
238
+ 发起 SSE 后**必须主动同步执行 `poll`** 等待结果:
239
+
240
+ ```bash
241
+ python3 {baseDir}/scripts/tcloud_async_task.py poll <chat_id> <session_id> 1200
242
+ ```
243
+
244
+ `poll` 命令会持续查询直到终态或超时。
245
+
246
+ **终端超时恢复**:若终端环境超时导致 `poll` 进程被 kill,Agent 只需**用同样的 `chat_id` + `session_id` 重新发起一次 `poll`**。后端任务状态持久化在服务端,不受终端生命周期影响。
247
+
248
+ **禁止行为**:在 poll 过程中(无论 `poll` 正在运行、终端超时还是结果未返回),**严禁发起新 SSE 对话**发送相同或类似的问题。只有累计 poll 超过 20 分钟仍为 `running` 时,重新发起 SSE 对话(回到 §4.1)。
249
+
250
+ | `poll` 返回 | 处理 |
251
+ |-------------|------|
252
+ | `completed` | **展示 Content**,停止 poll |
253
+ | `failed` | 告知 FinishReason,停止 poll |
254
+ | `cancelled/timeout` | 告知状态,重新发起 SSE 对话(回到 §4.1) |
255
+ | `not_found` | 重新发起 SSE 对话(回到 §4.1) |
256
+ | `PollTimeout`(超 20 分钟) | 重新发起 SSE 对话(回到 §4.1) |
257
+ | 终端超时(`poll` 被 kill) | 重新执行 `poll <chat_id> <session_id> 1200` |
258
+
259
+ 完整示例:
260
+
261
+ ```bash
262
+ # 发起
263
+ SID=$(python3 -c 'import uuid;print(uuid.uuid4())')
264
+ python3 {baseDir}/scripts/tcloud_sse_api.py '列出架构图' --source codebuddy --session-id "$SID"
265
+ # → {"chat_id":"d8gn4jpjqshmudtgk3qf","session_id":"27c5748c-e05e-4154-9b8d-8b9d94bd91eg","is_accepted":true}
266
+
267
+ # poll 等待结果(主动等待直到终态或超时)
268
+ python3 {baseDir}/scripts/tcloud_async_task.py poll d8gn4jpjqshmudtgk3qf 27c5748c-e05e-4154-9b8d-8b9d94bd91eg 1200
269
+ ```
270
+
271
+ ### 4.3 第三步:展示结果
272
+
273
+ `Content` 由脚本自动完成免密链接替换(仅 AK/SK 模式生效,OAuth/Connector 模式不生成免密链接)。若 Content 中包含免密登录链接(`login/roleAccessCallback`),用 `preview_url` 自动预览。
274
+
275
+ ### 4.4 取消任务
276
+
277
+ ```bash
278
+ python3 {baseDir}/scripts/tcloud_async_task.py cancel <chat_id> [session_id]
279
+ ```
280
+
281
+ ### 4.5 SessionID 管理(❗最高优先级)
282
+
283
+ > **SessionID 是服务端识别多轮对话的唯一标识。一旦改变,历史上下文全部丢失。**
284
+
285
+ 1. **首次对话**:生成 UUID v4 传入 `--session-id`
286
+ 2. **追问(同一对话中)**:**必须复用**首轮的 session_id,严禁重新生成
287
+ - 从当前对话上下文中回忆首轮传入的值
288
+ - 若不确定,用正则 `^\[session\] (\S+)` 从上一轮 stderr 回显提取
289
+ - **WorkBuddy/CodeBuddy 同一会话中的每次追问都是同一对话,必须用同一个 session_id**
290
+ 3. **新对话**:仅以下情形重新生成 UUID:
291
+ - 用户明确说"新对话"/"重新开始"/"换个话题"
292
+ - 平台会话重置(WorkBuddy 任务结束、CodeBuddy 新会话)
293
+ 4. **不采纳**后端返回的 session_id,始终使用调用方传入的值
294
+ 5. **严禁**用 `requestId` 代替 `session_id`(requestId 每次变化)
295
+
296
+ ### 4.6 协议同意
297
+
298
+ 首次调用可能返回协议同意请求(Content 含`软件许可及服务协议`或`请先阅读并同意`):
299
+ 1. 原样展示协议内容
300
+ 2. 等待用户回复"同意",**严禁自动发送**
301
+ 3. 用户同意后重新发起对话
302
+
303
+ ### 4.7 stdout 编码兜底
304
+
305
+ 若 stdout 出现中文乱码或 Markdown 损坏,改用输出重定向 + Read 工具:
306
+
307
+ ```bash
308
+ python3 {baseDir}/scripts/tcloud_async_task.py query <chat_id> <session_id> > /tmp/cloudq_response.txt 2>/tmp/cloudq_response_err.txt
309
+ ```
310
+
311
+ 用 Read 工具读取 `/tmp/cloudq_response.txt`(禁止 cat 回读),展示后清理临时文件。
312
+
313
+ > 这里用 `query` 而非 `poll`:因为已经是编码兜底场景,只需单次查询确认结果。
314
+
315
+ ---
316
+
317
+ ## 5. 错误处理
318
+
319
+ > 话术原则:**陈述事实 → 可能原因 → 下一步动作 → 给用户选择权**。
320
+
321
+ | 错误码 | 话术模板 | 重试 |
322
+ |--------|---------|------|
323
+ | `NeedAuth` | 「当前未找到可用凭证。需要先配置凭证才能使用 CloudQ。」 → 按 §2.4 引导配置 | ❌ |
324
+ | `MissingCredentials` | 「当前授权方式的凭证缺失,无法调用 API。」 → **仅提示用户**当前方式失败,告知可手动切换,**禁止自动切换** | ❌ |
325
+ | `CredentialExpired` | 「凭证已过期。」 → **OAuth**:提示用户重新授权,按 §2.1;**Connector(OneId)**:自动执行 §2.3 步骤 1-2 刷新后重试(同方式内刷新,非切换) | ✅ 同方式内 |
326
+ | `AuthFailure.UnauthorizedOperation` | 「当前凭证权限不足。建议为子账号关联 `ReadOnlyAccess` + `QcloudAdvisorAccessForCloudQ`。需要我提供配置步骤吗?」 | ❌ |
327
+ | `AuthFailure.SecretIdNotFound` | 「SecretId 无效。请检查当前授权方式的凭证是否正确。」 → 提示用户,**不切换** | ❌ |
328
+ | `AuthFailure.SignatureFailure` | 「SecretKey 校验失败。请检查当前授权方式的凭证是否正确。」 → 提示用户,**不切换** | ❌ |
329
+ | `NetworkError` | 「网络连接失败。要 30 秒后重试一次吗?」 | ✅ 1次 |
330
+ | `HTTPError` | 「服务端异常(临时抖动或升级)。要我重试一次吗?」 | ✅ 1次 |
331
+ | 空结果 | 「远端未返回具体结果。可能需要补充资源类型、地域等具体信息?」 | ⚠️ |
332
+ | OAuth / Connector 未配置凭证 | 「请前往 [CloudQ 控制台](https://console.cloud.tencent.com/advisor/cloudq) 完成凭证配置后再使用。」 | ❌ |
333
+
334
+ > **⚠️ 两种"凭证"的区别**:
335
+ > - **API 鉴权凭证**(AK/SK / OAuth / Connector(OneId)):用于签名调用 `CloudQChatCompletions` 接口。如果这些不对,接口直接返回鉴权错误(`AuthFailure.*`),根本走不到 CloudQ 服务逻辑。
336
+ > - **CloudQ 服务凭证**:在 [CloudQ 控制台](https://console.cloud.tencent.com/advisor/cloudq) 里配置给 CloudQ 使用的云 API 调用凭证。接口调通后,如果返回"尚未配置腾讯云凭证",说明 API 鉴权没问题,需要去控制台补配 **CloudQ 服务凭证**。
337
+
338
+ > **重试上限**:`NetworkError` / `HTTPError` 最多 1 次,连续失败告知稍后再试。
339
+
340
+ ---
341
+
342
+ ## 6. 安全约束
343
+
344
+ **AK/SK 仅限以下接口白名单**(严禁调用其他腾讯云 API):
345
+
346
+ | 接口 | 脚本 | 类型 |
347
+ |------|------|------|
348
+ | `advisor:CloudQChatCompletions` | `tcloud_sse_api.py` | 只读 |
349
+ | `advisor:DescribeCloudQAsyncTask` | `tcloud_async_task.py` | 只读 |
350
+ | `advisor:CancelCloudQAsyncTask` | `tcloud_async_task.py` | 写入 |
351
+ | `advisor:DescribeUserAuthorizationStatus` | `check_env.py` | 只读 |
352
+ | `advisor:CreateAdvisorAuthorization` | `check_env.py --enable-advisor` | 写入(需同意) |
353
+ | `sts:GetCallerIdentity` | `check_env.py` / `create_role.py` | 只读 |
354
+ | `sts:AssumeRole` | `login_url.py`(内部) | 敏感 |
355
+ | `cam:CreateRole` / `cam:AttachRolePolicy` / `cam:DeleteRole` | `create_role.py` / `cleanup.py` | 写入(需同意) |
356
+
357
+ - 凭证文件 `~/.tencent-cloudq/credential.json`(权限 600),存储 OAuth 或 Connector 凭证
358
+ - 网络仅连接 `*.tencentcloudapi.com`、`cloud.tencent.com`、`cloudq.cloud.tencent.com`、`clawhub.ai`
359
+ - 清理:`python3 {baseDir}/scripts/cleanup.py --all`(需 `--all` 参数)
@@ -0,0 +1,178 @@
1
+ # CloudQChatCompletions — CloudQ 全局对话
2
+
3
+ CloudQ 全局对话交互接口(SSE 流式输出),不绑定特定架构图,支持跨架构图的全局智能问答。
4
+
5
+ AK/SK 和 OAuth 两种鉴权方式统一使用此接口。
6
+
7
+ ## 对话模式
8
+
9
+ 始终使用异步模式,不区分场景:
10
+
11
+ | 模式 | 参数 | 说明 |
12
+ |------|------|------|
13
+ | **异步** | `Async=true`(固定使用) | 不受客户端 60s 超时限制 |
14
+
15
+ ### 为什么是异步?
16
+
17
+ 调用方终端环境(CodeBuddy/WorkBuddy/OpenClaw 等)通常有 **60 秒超时限制**,而 CloudQ 后端 SSE 编排正常耗时在 **5~10 分钟**,长任务最长可达 **20 分钟**。如果使用同步模式,客户端超时会直接断开连接,用户永远得不到结果。
18
+
19
+ 异步模式将"请求"与"结果获取"解耦:
20
+ 1. 发起异步请求 → 立即返回 accepted(< 1s,不受超时限制)
21
+ 2. 轮询查询结果 → 每次查询 < 1s,间隔可控
22
+
23
+ **因此所有调用一律使用异步模式。**
24
+
25
+ ## 调用示例
26
+
27
+ ```bash
28
+ # 发起异步请求
29
+ python3 {baseDir}/scripts/tcloud_sse_api.py '列出架构图' --source codebuddy --session-id <uuid>
30
+
31
+ # accepted 帧返回:
32
+ # {"success":true,"data":{"chat_id":"chat-xxx","session_id":"sess-xxx","content":"任务已受理...","is_accepted":true}}
33
+
34
+ # 查询任务状态(每次 <1s,不触发终端超时)
35
+ python3 {baseDir}/scripts/tcloud_async_task.py query <chat_id> <session_id>
36
+
37
+ # 取消任务
38
+ python3 {baseDir}/scripts/tcloud_async_task.py cancel <chat_id> [session_id]
39
+ ```
40
+
41
+ ## 参数
42
+
43
+ | 参数 | 必选 | 类型 | 描述 |
44
+ |------|------|------|------|
45
+ | Question | 是 | String | 用户问题,如 `列出架构图` |
46
+ | SessionID | 是 | String | 会话 ID(UUID v4),同一对话必须保持不变 |
47
+ | Source | 否 | String | 调用来源平台标识(不区分大小写),AI 根据当前运行环境自动判断,可选值:`codebuddy`、`workbuddy`、`openclaw`、`qclaw`、`hermes` 等 |
48
+ | Async | 否 | Boolean | 是否异步模式,默认 true。始终使用异步 |
49
+ | UseCloudQCredential | 否 | Boolean | OAuth 鉴权时自动设为 true,标识使用 CloudQ 控制台凭证 |
50
+ | UIRenderEvent | 否 | Boolean | 是否返回结构化 UI 事件 |
51
+ | Messages | 否 | Array | 历史消息上下文 |
52
+ | Model | 否 | String | 模型名称 |
53
+
54
+ ## 返回格式
55
+
56
+ ### 异步 accepted 帧
57
+
58
+ ```json
59
+ {
60
+ "success": true,
61
+ "action": "CloudQChatCompletions",
62
+ "data": {
63
+ "session_id": "049bbd09-c5c9-48fa-b9c0-8952d94e53fe",
64
+ "content": "当前账号下共有 **10 张**架构图...\n\n[前往智能顾问控制台](免密登录URL)",
65
+ "is_final": true
66
+ },
67
+ "requestId": "d72bal4g699bmj4h7gs0"
68
+ }
69
+ ```
70
+
71
+ ### 异步模式(accepted 帧)
72
+
73
+ ```json
74
+ {
75
+ "success": true,
76
+ "action": "CloudQChatCompletions",
77
+ "data": {
78
+ "chat_id": "chat-7f3a9b2e1d4c",
79
+ "session_id": "sess-e5b8c1a0f6d2",
80
+ "content": "任务已受理...",
81
+ "is_accepted": true
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### 异步任务查询结果(DescribeCloudQAsyncTask)
87
+
88
+ ```json
89
+ {
90
+ "success": true,
91
+ "action": "DescribeCloudQAsyncTask",
92
+ "data": {
93
+ "Status": "completed",
94
+ "FinishReason": "stop",
95
+ "Content": "根据您的云架构分析,建议优化以下资源配置...",
96
+ "SessionID": "sess-e5b8c1a0f6d2",
97
+ "ChatID": "chat-7f3a9b2e1d4c"
98
+ }
99
+ }
100
+ ```
101
+
102
+ ## 返回字段说明
103
+
104
+ | 字段 | 类型 | 说明 |
105
+ |------|------|------|
106
+ | `session_id` | String | **会话 ID**(UUID v4),用于标识同一轮对话。多轮对话时必须传入此值以保持上下文 |
107
+ | `content` | String | Markdown 格式回答(控制台链接已自动替换为免密登录链接) |
108
+ | `is_final` | Boolean | 是否为最终结果 |
109
+ | `requestId` | String | 请求追踪 ID(仅用于日志排查,**不能用作会话标识**) |
110
+
111
+ 异步模式额外字段:
112
+
113
+ | 字段 | 类型 | 说明 |
114
+ |------|------|------|
115
+ | `chat_id` | String | 异步任务 ID,用于后续 `DescribeCloudQAsyncTask` 查询 |
116
+ | `is_accepted` | Boolean | 是否为 accepted 帧(异步模式) |
117
+
118
+ ## FinishReason 枚举
119
+
120
+ | 值 | 含义 | 出现场景 |
121
+ |----|------|----------|
122
+ | `stop` | 正常完成 | 编排自然结束 |
123
+ | `user_stopped` | 用户主动停止 | `CancelCloudQChat` / `CancelCloudQAsyncTask` 触发 |
124
+ | `timeout` | 执行超时 | 编排超过时间上限自动终止 |
125
+ | `error` | 执行异常 | panic / 系统错误 |
126
+
127
+ ## 脚本自动处理(无需手动干预)
128
+
129
+ `tcloud_sse_api.py` 在返回 content 前会自动执行以下处理:
130
+
131
+ 1. 扫描 `console.cloud.tencent.com` 链接,替换为免密登录链接
132
+ 2. 如果链接不含 archId 但内容中有架构图 ID(`arch-xxx`),自动拼入
133
+ 3. 自动追加 `hideTopNav=true` 参数
134
+ 4. 已是免密登录链接的不会重复处理
135
+ 5. 免密链接生成失败时保留原链接
136
+ 6. 如果 content 中没有任何免密链接,自动在末尾追加 `[前往智能顾问控制台](免密登录URL)`
137
+
138
+ ## 展示规则
139
+
140
+ - `content` **已包含免密登录链接**,可直接展示给用户,无需额外生成
141
+ - 严禁直接展示完整免密登录 URL,必须以 Markdown 超链接格式展示
142
+
143
+ ## 错误返回
144
+
145
+ 调用失败时返回统一错误格式,**必须将错误码和错误信息展示给用户**:
146
+
147
+ ```json
148
+ {
149
+ "success": false,
150
+ "action": "CloudQChatCompletions",
151
+ "error": {
152
+ "code": "UnauthorizedOperation",
153
+ "message": "The operator is not authorized."
154
+ },
155
+ "requestId": "18b169de-4e4e-46d9-80ff-53053f34b0d7"
156
+ }
157
+ ```
158
+
159
+ ## 常见错误码
160
+
161
+ | 错误码 | 说明 | 处理方式 |
162
+ |--------|------|---------|
163
+ | `AuthFailure.SecretIdNotFound` | SecretId 不存在 | 提示用户检查 AK/SK 配置 |
164
+ | `AuthFailure.SignatureFailure` | 签名验证失败 | 提示用户检查 SecretKey 是否正确 |
165
+ | `AuthFailure.InvalidSecretId` | SecretId 无效 | 提示用户检查 AK/SK 配置 |
166
+ | `UnauthorizedOperation` | 无操作权限 | 提示用户当前账号无权调用此接口,需授权 `QcloudAdvisorFullAccess` 策略 |
167
+ | `UnauthorizedOperation.CamUnauthorized` | CAM 鉴权未通过 | 提示用户为子账号授予智能顾问相关权限 |
168
+ | `FailedOperation` | 操作失败 | 将错误信息原样展示给用户 |
169
+ | `ResourceNotFound` | 资源不存在 | 提示用户可能未开通智能顾问,调用 `DescribeUserAuthorizationStatus` 确认 |
170
+ | `RequestLimitExceeded` | 请求频率超限 | 提示用户稍后重试 |
171
+ | `ErrMissingParameter` | 必填参数缺失 | 检查 ChatID/SessionID 是否传入 |
172
+ | `ErrOperationDenied` | 无权操作 | 跨用户访问被拒绝 |
173
+
174
+ ## 错误处理规则
175
+
176
+ 1. **必须将 `error.code` 和 `error.message` 展示给用户**,不可吞掉错误
177
+ 2. 权限类错误(`UnauthorizedOperation`、`AuthFailure.*`)需提示用户检查账号权限或 AK/SK 配置
178
+ 3. 未开通类错误需引导用户通过 `DescribeUserAuthorizationStatus` 确认后决定是否开通