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,12 +1,12 @@
---
name: configuring-compute
description: >-
Configure compute providers (model API endpoints and API keys) for the user
via the Agent Service HTTP API: create/update providers, write API keys
(write-only), verify them, and reload the configuration. Use when the user
asks to add or configure a model provider, set an API key, or fix compute
configuration. 用户要求配置算力、添加模型供应商或设置 API Key 时使用。
version: 1.0.3
Configure DesireCore compute providers through governed tools: inspect,
enable or disable providers, sync models, and set API keys without reading
them back. Use the dedicated DesireCore GUI tool for fields not yet covered
by ManageCompute. Never call renderer-only /api/compute management endpoints
from Bash or HttpRequest. 用户要求配置算力、同步模型或设置 API Key 时使用。
version: 1.1.0
type: meta
risk_level: medium
status: enabled
@@ -18,7 +18,7 @@ tags:
- meta
metadata:
author: desirecore
updated_at: '2026-07-29'
updated_at: '2026-08-30'
i18n:
default_locale: en-US
source_locale: zh-CN
@@ -29,22 +29,23 @@ metadata:
name: 配置算力
short_desc: 帮用户配置模型供应商与 API Key密钥只写不读
description: >-
通过 Agent Service HTTP API 为用户配置算力供应商(模型 API 端点与 API Key
创建/更新 provider、写入 API Key只写、验证密钥、刷新配置。
Use when 用户要求添加或配置模型供应商、设置 API Key、修复算力配置
通过受治理工具配置 DesireCore 算力:查看和启停 provider、同步模型、只写 API Key
ManageCompute 尚未覆盖的字段使用专用 DesireCore GUI 工具。禁止从 Bash 或 HttpRequest
调用仅供可信渲染器使用的 /api/compute 管理端点
body: ./SKILL.zh-CN.md
translated_by: human
source_hash: sha256:b37d5baa849e88e9
en-US:
name: Configure Compute
short_desc: Configure model providers and API keys for the user (keys are write-only)
description: >-
Configure compute providers (model API endpoints and API keys) for the user
via the Agent Service HTTP API: create/update providers, write API keys
(write-only), verify them, and reload the configuration. Use when the user
asks to add or configure a model provider, set an API key, or fix compute configuration.
Configure DesireCore compute through governed tools: inspect and enable providers,
sync models, and write API keys without reading them back. Use the dedicated
DesireCore GUI tool for fields not covered by ManageCompute; never call renderer-only
/api/compute management endpoints from Bash or HttpRequest.
body: ./SKILL.md
translated_by: human
source_hash: sha256:15e9247a2c27edf7
source_hash: sha256:b37d5baa849e88e9
market:
icon: >-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6" rx="1"/><path d="M9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2"/></svg>
@@ -57,140 +58,76 @@ market:
# Configure Compute
Help the user configure compute providers — model API endpoints and API keys —
through the Agent Service HTTP API.
Configure DesireCore compute through governed tools. Do not call the local
`/api/compute/*` management endpoints from Bash, HttpRequest, or scripts: those
endpoints intentionally require a trusted renderer Origin and instance token.
## Security model (read this first, non-negotiable)
## Security contract
- **API keys are write-only.** You can create and overwrite keys; you can NEVER
read an existing key back. There is no API that returns key plaintext to you,
`GET /api/compute/config` returns masked values only, and the runtime blocks
file reads of `secrets.json` (Read/Grep tools and shell commands alike).
- **Do not try to work around this.** Never attempt to read
`~/.desirecore/config/secrets.json`, never echo a key the user gave you back
into chat more than necessary, never store keys anywhere except via
`POST /api/compute/secrets`.
- If the user asks "what is my current key", answer: keys cannot be read back;
they can only be replaced. Point them to the provider settings UI, which has
a user-only reveal control.
- API keys are write-only for agents. Never read `secrets.json`, request
`ComputeCredential(action='get', raw=true)`, or repeat a key in tool results or chat.
- Use `ComputeCredential(action='set')` to create or replace the key of an
existing user-managed provider. If the provider has no credential reference,
the tool creates and attaches one without returning the plaintext. This path
is approval-gated and audited; approval cards, tool events, receipts, and
session history redact the sensitive value. System-managed credentials are
not writable.
- Pass a value to `ComputeCredential(action='set')` only when the user already supplied the
replacement key in the current request. If the agent must never handle the
plaintext, use the GUI to focus the password field, let the user type into it
directly, then continue the save flow. Never ask for the key in ordinary chat
or read the masked field back into the model.
- `credentialMode=none` means the provider needs no key. Ollama is treated as
`none` even when an older config does not declare the field.
- If the user asks for the current key, explain that the agent can replace it but
cannot read it back. The human-only UI reveal flow remains separate.
## How to call the API
## Workflow for an existing provider
- Prefer the `Bash` tool with `curl`. The API base URL is already injected into
the "Local API" section of the system prompt; reference it directly.
- On Windows without Git Bash, use the `HttpRequest` tool with the same URLs.
First confirm `ManageCompute` is available through the current tool catalog. If
it is absent (for example on an older installed client), use the governed GUI
workflow below for the whole task; do not fall back to local HTTP.
## Workflow
1. Call `ManageCompute(action='list')`. Record the exact provider ID,
enabled state, credential mode, status, and model count.
2. If credential mode is `required` and the user supplied a new key in the
current request, call `ComputeCredential(action='set', providerId=..., value=...)`.
Do not echo the value. If the agent must not handle plaintext,
use the human-entry GUI flow below. For `none`, skip this step.
3. Call `ManageCompute(action='set_enabled', providerId=..., enabled=true)`.
4. Call `ManageCompute(action='sync_models', providerId=...)`. For Ollama
this discovers locally installed models; for supported cloud providers it
merges the built-in model list.
5. Call `InspectModels` to verify the intended model is selectable. When the
user asked for a real test, run one short fixed-model conversation and verify
the run receipt names the requested provider/model.
### 1. Inspect current configuration
Mutating ManageCompute and ComputeCredential operations use the platform's
approval policy. Do not add a second confirmation in prose unless information
is missing or the user requested a destructive replacement.
```bash
curl -s $BASE/api/compute/config
```
## Fields not yet covered by ManageCompute
Response contains `providers[]` where `apiKey` is a **masked display value**
(first 4 chars + bullets) and `hasApiKey: boolean` tells you whether a key is
configured. Use this to decide between creating a new provider and updating an
existing one. Never treat the masked `apiKey` as a real key.
Creating a new custom provider, changing base URL/API format, deleting a
provider, and interactive key verification currently remain GUI operations.
Use `ControlDesireCoreGui`, not a generic browser/CUA tool:
### 2. Create a provider (if needed)
1. `list_instances`, then `begin(instance=<id>, mode=control, reason=...)` for
the intended DesireCore instance. The default `observe` mode is read-only and
cannot modify compute settings.
2. Use the governed CDP methods to open Resources → Compute and make the change.
3. Finish with `end`. If `ManageCompute` exists, call `ManageCompute(action='list')`; on
an older client, verify the saved state in the GUI instead. Call
`InspectModels` when available to confirm model selection.
```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"
}'
```
If the installed version includes `ControlDesireCoreGui` but reports that GUI
control is disabled, the owner must set
`config/security.json#desktopGuiControl.enabled=true` and restart that instance.
If the tool is absent from the catalog entirely, the client is too old and must
be upgraded; changing the switch cannot add a missing tool. Do not bypass the
renderer HTTP boundary.
Required fields: `provider`, `label`, `baseUrl`, `services`. The response
returns the created provider with its generated `id` — keep it for later steps.
Known provider presets and model lists are available via
`GET /api/compute/pi-providers` and `GET /api/compute/pi-models/:provider`.
## Completion report
### 3. Set the API key (write-only)
Ask the user for the key. Reuse the provider's existing `apiKeyRef` if set;
otherwise generate one like `key-<random>` and attach it to the provider:
```bash
# Write the secret (write-only endpoint; there is no GET counterpart)
curl -s -X POST $BASE/api/compute/secrets \
-H 'Content-Type: application/json' \
-d '{"ref": "key-abc123", "value": "<API_KEY_FROM_USER>"}'
# Attach the ref to the provider if it was not set yet
curl -s -X PUT $BASE/api/compute/providers/<id> \
-H 'Content-Type: application/json' \
-d '{"apiKeyRef": "key-abc123"}'
```
### 4. Verify the key
```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"}'
```
Returns `{ valid, latencyMs, errorMessage?, suggestedBaseUrl? }`. If
`suggestedBaseUrl` is present, offer to update the provider's `baseUrl`.
### 5. Enable and populate models
```bash
curl -s -X PUT $BASE/api/compute/providers/<id> \
-H 'Content-Type: application/json' -d '{"enabled": true}'
# Optional: sync the model list from the built-in registry
curl -s -X POST $BASE/api/compute/sync-models/<id>
```
### 6. Reload so the UI reflects the change
Always finish with:
```bash
curl -s -X POST $BASE/api/compute/reload
```
This re-validates the configuration and broadcasts a refresh event to the
client UI. Report the returned `providerCount` / `enabledProviderCount` /
`modelCount` to the user as confirmation.
## Endpoint reference
| Method | Path | Purpose |
| ------ | ---- | ------- |
| GET | `/api/compute/config` | Full config; `apiKey` masked + `hasApiKey` |
| POST | `/api/compute/providers` | Create provider |
| PUT | `/api/compute/providers/:id` | Patch provider (label/baseUrl/enabled/apiFormat/apiKeyRef/...) |
| DELETE | `/api/compute/providers/:id` | Remove provider |
| POST | `/api/compute/secrets` | Write key `{ref, value}`**write-only** |
| DELETE | `/api/compute/secrets/:ref` | Delete key |
| POST | `/api/compute/verify-key` | Probe a key end-to-end |
| POST | `/api/compute/sync-models/:id` | Sync model list from registry |
| POST | `/api/compute/reload` | Re-validate config + broadcast UI refresh |
| GET | `/api/compute/pi-providers` | Known provider presets |
| GET | `/api/compute/pi-models/:provider` | Known models for a preset |
## Error handling
| Symptom | Cause | Action |
| ------- | ----- | ------ |
| 400 on create | Missing required field / unknown field | Fix the request body (schema is strict, `additionalProperties: false`) |
| 404 on PUT | Wrong provider id | Re-list via GET config |
| `valid: false` on verify | Wrong key / wrong baseUrl / wrong apiFormat | Show `errorMessage` to the user; try `suggestedBaseUrl` if present |
| 403 anywhere | You tried a credential-gated endpoint (key reveal) | Stop — that endpoint is for the human user's UI only |
## Confirmation etiquette
- Before overwriting an existing key (`hasApiKey: true`), confirm with the user.
- Before deleting a provider or key, confirm with the user.
- After finishing, summarize what changed (provider, enabled state, model count)
without repeating the key value.
Report the provider ID, enabled state, synchronized model count, and model test
result. Never include the key, its encrypted storage, or a plaintext fingerprint.