fix(skill): 修正算力配置治理流程 (#100)

## 中文

- 将算力配置流程改为 `ManageCompute` 与 `ComputeCredential set`
- 明确密钥只允许写入且工具结果保持脱敏
- 补全 GUI `mode=control` 回退、旧客户端条件化验证和升级提示
- 禁止引导 Agent 绕过 renderer Origin/token 边界

## English

- Route compute configuration through `ManageCompute` and
`ComputeCredential set`
- Keep credentials write-only and redacted from tool results
- Complete the GUI `mode=control` fallback, legacy-client validation,
and upgrade guidance
- Stop directing Agents around renderer Origin/token protections

## Validation

- Translation freshness check
- Skill i18n validation
- `git diff --check`
This commit is contained in:
2026-08-29 14:26:24 -04:00
committed by GitHub
parent a625b5ec84
commit 54716ea43a
3 changed files with 127 additions and 256 deletions

View File

@@ -1,130 +1,57 @@
# 配置算力
通过 Agent Service HTTP API 帮用户配置算力供应商——模型 API 端点与 API Key。
通过受治理工具配置 DesireCore 算力。禁止从 Bash、HttpRequest 或脚本调用本机
`/api/compute/*` 管理端点;这些端点有意要求可信渲染器 Origin 和实例令牌。
## 安全模型(先读这里,不可协商)
## 安全契约
- **API Key 只写不读。** 你可以创建和覆盖密钥,但**永远无法**读回已有密钥。
没有任何 API 会向你返回密钥明文:`GET /api/compute/config` 只返回掩码值,
运行时同时拦截对 `secrets.json` 的文件读取Read/Grep 工具与 shell 命令一律拒绝)。
- **不要尝试绕过。** 不要读取 `~/.desirecore/config/secrets.json`,不要在对话中
超出必要地回显用户提供的密钥,除 `POST /api/compute/secrets` 外不要在任何地方存放密钥。
- 如果用户问「我现在的 key 是什么」,回答:密钥无法读回,只能替换;
可引导用户到供应商设置页,那里有仅限用户本人的明文查看控件。
- 对 Agent 而言 API Key 只写不读。不得读取 `secrets.json`、请求
`ComputeCredential(action='get', raw=true)`,也不得在工具结果或聊天中复述密钥。
- 使用 `ComputeCredential(action='set')` 为已有的用户自管 Provider 创建或替换密钥。若该
Provider 尚无凭据引用,工具会创建并挂载专属引用,但不会把明文返回给 Agent。此路径
受审批、留审计;敏感值在审批卡、工具事件、回执和会话历史中统一脱敏,系统托管凭据
不可由该操作覆盖。
- 只有当用户已经在当前请求中主动提供了替换密钥时,才把该值传给
`ComputeCredential(action='set')`;若要求
Agent 从未接触明文,则用 GUI 聚焦密码输入框,让用户直接输入后再继续保存。不得让用户
把密钥发到普通聊天,也不得把掩码字段读回模型。
- `credentialMode=none` 表示 Provider 无需密钥。旧配置未声明时Ollama 也按 `none` 处理。
- 用户询问当前 Key 时,说明 Agent 只能替换、不能读回;人类 UI 的明文查看流程保持独立。
## 如何调用 API
## 已有 Provider 的工作流程
- 优先使用 `Bash` 工具 + `curl`。API 基础地址已注入到 system prompt 的
「本机 API」小节直接引用即可
- Windows 无 Git Bash 时,用 `HttpRequest` 工具调用相同 URL。
先通过当前工具目录确认 `ManageCompute` 可用。若工具不存在(例如安装版客户端较旧),
整项任务改走下方受治理 GUI 流程;不得回退到本地 HTTP
## 工作流程
1. 调用 `ManageCompute(action='list')`,记录准确的 Provider ID、启用状态、凭据模式、状态和模型数。
2. 若凭据模式为 `required` 且用户已在当前请求中提供新密钥,调用
`ComputeCredential(action='set', providerId=..., value=...)`;不得回显。若用户要求 Agent 不接触明文,改走
下方 GUI 人工直填密码框。凭据模式为 `none` 时跳过。
3. 调用 `ManageCompute(action='set_enabled', providerId=..., enabled=true)`
4. 调用 `ManageCompute(action='sync_models', providerId=...)`。Ollama 会发现本机已安装模型;
支持的云 Provider 会合并内置模型清单。
5. 调用 `InspectModels` 确认目标模型可选。若用户要求真实测试,发起一次简短固定模型对话,
并核对运行回执中的 Provider/模型就是目标项。
### 1. 查看当前配置
ManageCompute 和 ComputeCredential 的变更操作会走平台审批策略。除非信息缺失或用户要求
破坏性替换,不要在文字里再加一层重复确认。
```bash
curl -s $BASE/api/compute/config
```
## ManageCompute 尚未覆盖的字段
响应中的 `providers[]``apiKey` 是**掩码展示值**(前 4 位 + 圆点),
`hasApiKey: boolean` 表示是否已配置密钥。据此决定是新建 provider 还是更新现有的。
掩码 `apiKey` 不是真实密钥,不要当作密钥使用。
新建自定义 Provider、修改 Base URL/API 格式、删除 Provider、交互式验证密钥目前仍走 GUI。
使用 `ControlDesireCoreGui`,不要使用通用浏览器/CUA 工具:
### 2. 创建 provider如需要
1. `list_instances`,再对目标 DesireCore 实例执行
`begin(instance=<id>, mode=control, reason=...)`。默认 `observe` 只能读取界面,不能修改算力。
2. 用受治理 CDP 方法进入“资源 → 算力”完成修改。
3. 执行 `end`。若当前版本有 `ManageCompute`,再调用 `ManageCompute(action='list')`;旧客户端则在 GUI
内复核保存状态。`InspectModels` 可用时再用它确认模型可选。
```bash
curl -s -X POST $BASE/api/compute/providers \
-H 'Content-Type: application/json' \
-d '{
"provider": "deepseek",
"label": "DeepSeek",
"baseUrl": "https://api.deepseek.com",
"services": ["chat"],
"apiFormat": "openai-completions",
"priceCurrency": "CNY"
}'
```
若当前版本包含 `ControlDesireCoreGui`,但工具报告 GUI 控制已关闭,实例所有者需设置
`config/security.json#desktopGuiControl.enabled=true` 并重启该实例。若工具目录里完全没有该工具,
说明客户端版本过旧,必须升级;修改开关不能补出旧版本不存在的工具。不得绕过渲染器 HTTP 边界。
必填字段:`provider``label``baseUrl``services`。响应返回创建的 provider
及其生成的 `id`——后续步骤要用。已知供应商预设与模型列表可通过
`GET /api/compute/pi-providers``GET /api/compute/pi-models/:provider` 获取。
## 完成交付
### 3. 设置 API Key只写
向用户索取密钥。provider 已有 `apiKeyRef` 则复用;否则生成一个形如
`key-<随机串>` 的引用名并挂到 provider 上:
```bash
# 写入密钥(只写端点,没有对应的 GET
curl -s -X POST $BASE/api/compute/secrets \
-H 'Content-Type: application/json' \
-d '{"ref": "key-abc123", "value": "<用户提供的API_KEY>"}'
# 如果 provider 还没有 apiKeyRef补挂上去
curl -s -X PUT $BASE/api/compute/providers/<id> \
-H 'Content-Type: application/json' \
-d '{"apiKeyRef": "key-abc123"}'
```
### 4. 验证密钥
```bash
curl -s -X POST $BASE/api/compute/verify-key \
-H 'Content-Type: application/json' \
-d '{"provider": "deepseek", "baseUrl": "https://api.deepseek.com", "apiKeyRef": "key-abc123", "apiFormat": "openai-completions"}'
```
返回 `{ valid, latencyMs, errorMessage?, suggestedBaseUrl? }`。若返回
`suggestedBaseUrl`,主动提议更新 provider 的 `baseUrl`
### 5. 启用并填充模型
```bash
curl -s -X PUT $BASE/api/compute/providers/<id> \
-H 'Content-Type: application/json' -d '{"enabled": true}'
# 可选:从内置注册表同步模型列表
curl -s -X POST $BASE/api/compute/sync-models/<id>
```
### 6. 刷新配置让 UI 生效
收尾必做:
```bash
curl -s -X POST $BASE/api/compute/reload
```
该端点重新校验配置并向客户端 UI 广播刷新事件。把返回的 `providerCount` /
`enabledProviderCount` / `modelCount` 报告给用户作为完成确认。
## 端点速查
| 方法 | 路径 | 用途 |
| ---- | ---- | ---- |
| GET | `/api/compute/config` | 完整配置;`apiKey` 为掩码 + `hasApiKey` |
| POST | `/api/compute/providers` | 创建 provider |
| PUT | `/api/compute/providers/:id` | 局部更新label/baseUrl/enabled/apiFormat/apiKeyRef/... |
| DELETE | `/api/compute/providers/:id` | 删除 provider |
| POST | `/api/compute/secrets` | 写入密钥 `{ref, value}` —— **只写** |
| DELETE | `/api/compute/secrets/:ref` | 删除密钥 |
| POST | `/api/compute/verify-key` | 端到端验证密钥 |
| POST | `/api/compute/sync-models/:id` | 从注册表同步模型列表 |
| POST | `/api/compute/reload` | 重新校验配置 + 广播 UI 刷新 |
| GET | `/api/compute/pi-providers` | 已知供应商预设 |
| GET | `/api/compute/pi-models/:provider` | 预设供应商的已知模型 |
## 错误处理
| 现象 | 原因 | 处理 |
| ---- | ---- | ---- |
| 创建时 400 | 缺必填字段 / 携带未知字段 | 修正请求体schema 严格,`additionalProperties: false` |
| PUT 时 404 | provider id 错误 | 重新 GET config 拿列表 |
| 验证 `valid: false` | 密钥错 / baseUrl 错 / apiFormat 错 | 把 `errorMessage` 转告用户;有 `suggestedBaseUrl` 则尝试 |
| 任何端点 403 | 误触凭证门控端点(明文查看) | 立即停止——该端点仅供人类用户的 UI 使用 |
## 确认礼仪
- 覆盖已有密钥(`hasApiKey: true`)前,先向用户确认。
- 删除 provider 或密钥前,先向用户确认。
- 完成后向用户总结变更内容provider、启用状态、模型数量不要复述密钥值。
报告 Provider ID、启用状态、同步后的模型数量和真实模型测试结果。不要包含密钥、加密存储内容
或明文指纹。