diff --git a/builtin-skills.json b/builtin-skills.json index d39fbc7..e6e46eb 100644 --- a/builtin-skills.json +++ b/builtin-skills.json @@ -17,10 +17,12 @@ "pdf", "pptx", "python-runtime", + "registering-services", "s3-storage-operations", "skill-creator", "tech-diagram", "update-agent", + "using-services", "web-access", "workflow", "xiaomi-tts", diff --git a/manifest.json b/manifest.json index d90f6ad..996cd27 100644 --- a/manifest.json +++ b/manifest.json @@ -27,8 +27,8 @@ }, "stats": { "totalAgents": 1, - "totalSkills": 22, - "lastUpdated": "2026-05-30" + "totalSkills": 24, + "lastUpdated": "2026-05-31" }, "features": [ "verified-only", diff --git a/skills/registering-services/SKILL.md b/skills/registering-services/SKILL.md new file mode 100644 index 0000000..6355643 --- /dev/null +++ b/skills/registering-services/SKILL.md @@ -0,0 +1,198 @@ +--- +name: registering-services +description: >- + Register an external HTTP/MCP service to the global Application & Service + Catalog so that other Agents (and the human user) can discover and call it. + Use when the user mentions adding a new service, registering an API, or + publishing a backend you control to the team's catalog. 新增服务、注册 API、把后端发布到团队目录时使用。 +version: 1.0.0 +type: meta +risk_level: medium +status: enabled +disable-model-invocation: true +tags: + - service + - registration + - catalog + - meta +metadata: + author: desirecore + updated_at: '2026-05-28' + i18n: + default_locale: en-US + source_locale: zh-CN + locales: + - zh-CN + - en-US + zh-CN: + name: 注册服务 + short_desc: 把外部 HTTP/MCP 服务登记到全局应用与服务目录 + description: >- + 把外部 HTTP/MCP 服务登记到全局应用与服务目录,让其他 Agent 与人类用户都能发现并调用。 + Use when 用户提到要新增服务、注册 API 或把你掌握的后端发布到团队目录。 + body: ./SKILL.zh-CN.md + translated_by: human + en-US: + name: Register Services + short_desc: Register external HTTP/MCP services into the global catalog + description: >- + Register an external HTTP/MCP service to the global Application & Service Catalog so that other Agents (and the human user) can discover and call it. Use when the user mentions adding a new service, registering an API, or publishing a backend you control to the team's catalog. + body: ./SKILL.md + translated_by: human +market: + category: productivity + maintainer: + name: DesireCore Official + verified: true + channel: latest +--- + +# registering-services Skill + +## L0: One-line Summary + +Tell the Agent how to register an external HTTP/MCP service into the global +catalog with human governance. + +## L1: Overview + +This meta-skill teaches you (the Agent) **how** to add a new service to the +shared "Apps & Services" catalog. It does **not** invoke external services +itself — once registered, use the per-service Skill at `~/.desirecore/skills/svc-/` +or the `using-services` meta-skill to actually call them. + +### When to use this skill + +- The user asks to register an API or service (e.g. "add the Acme search + endpoint to our catalog") +- You just deployed a backend you want other Agents to be able to reach +- You discover a useful public API and want to make it shareable + +### When NOT to use it + +- One-off HTTP calls that nobody else needs to repeat — just call `HttpRequest` + directly +- Adding an MCP server to **your own** agent only — POST to + `/api/agents//mcp-servers` instead, no catalog entry needed +- Modifying an existing catalog entry — the user must promote/reject through + the Store UI + +## L2: How to register a service + +### Step 1 — Gather the required fields + +Before calling the API, collect: + +| Field | Required | Notes | +|------|----------|-------| +| `id` | yes | kebab-case, globally unique (e.g. `acme-search-api`) | +| `name` | yes | Human-readable display name | +| `description` | yes | One sentence — what it does | +| `protocol` | yes | `'http'` or `'mcp'` | +| `tags` | yes | Searchable list, e.g. `['search', 'web']` | +| `registeredBy` | yes | **Your own agent id** | +| `endpoint` | **required when `protocol='http'`** | Base URL of the API | +| `riskLevel` | recommended | `low` / `medium` / `high` / `critical` | +| `auth` | when API requires auth | `{ type, secretRef }` — see below | +| `operations` | recommended | Operations list for the per-service Skill | +| `capabilities` | optional | What this service can do | + +### Step 2 — Choose `riskLevel` honestly + +`riskLevel` decides whether **future calls** to this service trigger an +approval gate: + +- `low` — read-only data that's safe to invoke without prompting (e.g. public weather API) +- `medium` — default for most APIs; first invoke per session may prompt +- `high` — services that move money, send emails, mutate user data +- `critical` — services that can cause irreversible harm; **every** call requires human approval + +**Bias toward higher risk if uncertain.** Under-classifying is worse than over-classifying. + +### Step 3 — Reference credentials with `secretRef`, never inline + +**Do not put API keys/tokens into the catalog entry.** The catalog is global, +visible in the Store UI, and may be inspected by future people. Instead: + +```jsonc +{ + "auth": { + "type": "bearer", + "secretRef": "secrets/api-keys/acme" // pointer, not the actual key + } +} +``` + +`HttpRequest` resolves `secretRef` at call time. If the secret doesn't exist +yet, ask the user to provide it through their own secrets manager — not +through the chat. + +### Step 4 — Call the registration API + +Use the `HttpRequest` tool to POST to the local Agent Service: + +```yaml +tool: HttpRequest +parameters: + url: http://127.0.0.1:/api/registry/agent-services + method: POST + body: + id: acme-search-api + name: "Acme Search API" + description: "Full-text search across Acme's product catalog" + protocol: http + endpoint: https://api.acme.example/search + tags: ["search", "products"] + registeredBy: "" + riskLevel: medium + auth: + type: bearer + secretRef: secrets/api-keys/acme + operations: + - name: search + method: GET + path: /v1/items + description: "Search products by query string" + - name: getDetail + method: GET + path: /v1/items/{id} + description: "Get a single product by id" +``` + +(The Agent Service port is available via the runtime; ask `request-help` +skill if you're unsure how to discover it.) + +### Step 5 — Wait for human approval + +The endpoint triggers a **service-approval** request to the human user. The +HTTP call will block until they approve or reject through the Store UI. + +- **Approved** → entry is written to + `~/.desirecore/config/registry-agent-services.json` with + `reviewStatus: 'pending'`. While `pending`, **only you** (the registering + Agent) can call it. +- **Rejected** → the API returns 403; do not retry, ask the user how to + proceed. + +After approval, the human can later **promote** the entry from `pending` to +`approved` in the Store UI. Promotion makes the service callable by all +Agents and triggers `service-skill-generator` to write +`~/.desirecore/skills/svc-/SKILL.md` with concrete examples derived +from the `operations` you provided. + +### Step 6 — Don't re-register + +If `POST /api/registry/agent-services` returns `409 Conflict`, the service +already exists. Do not try alternative ids unless the user explicitly asks +you to register a separate variant — silently shadowing an existing service +is a governance failure. + +## Failure modes + +- **Endpoint blocked by SSRF guard**: the registration API rejects private + network addresses (10.x / 172.16-31.x / 192.168.x / 169.254.x) except + localhost. Public IPs and DNS names are allowed. +- **Missing `registeredBy`**: the API returns 400. Always include your own + agent id — there is no anonymous registration. +- **Approval timeout**: the broker times out after the user is idle long + enough; treat this as `rejected`. diff --git a/skills/registering-services/SKILL.zh-CN.md b/skills/registering-services/SKILL.zh-CN.md new file mode 100644 index 0000000..403e8b1 --- /dev/null +++ b/skills/registering-services/SKILL.zh-CN.md @@ -0,0 +1,135 @@ + + +# 注册服务(registering-services) + +## L0:一句话总结 + +教会 Agent 如何把一个外部 HTTP/MCP 服务安全地登记进全局"应用与服务目录", +并经人类用户审批。 + +## L1:概述 + +这是一个 **元技能**,告诉你(Agent)**怎么** 把新服务添加进共享的"应用与服务目录"。 +本技能 **不负责** 调用外部服务 —— 注册成功且 approved 后,请用 +`~/.desirecore/skills/svc-/` 下的专属 Skill 或者 `using-services` +元技能来真正发起调用。 + +### 何时使用 + +- 用户让你"把 X API 注册到目录里" +- 你刚部署了某个后端,希望别的 Agent 能用到 +- 你发现一个有用的公共 API,想让团队共享 + +### 何时不要用 + +- 一次性 HTTP 调用,别人不需要重复用 —— 直接 `HttpRequest` 即可 +- 只给 **自己这个 Agent** 加 MCP 服务 —— 直接 POST `/api/agents//mcp-servers`,无需目录条目 +- 修改已有目录条目 —— 必须由用户在 Store UI 提升 / 拒绝 + +## L2:如何注册一个服务 + +### Step 1 — 收集必填字段 + +调用 API 前,先准备好: + +| 字段 | 必填 | 说明 | +|------|------|------| +| `id` | 是 | kebab-case,全局唯一(如 `acme-search-api`) | +| `name` | 是 | 显示名 | +| `description` | 是 | 一句话功能描述 | +| `protocol` | 是 | `'http'` 或 `'mcp'` | +| `tags` | 是 | 搜索标签数组,如 `['search', 'web']` | +| `registeredBy` | 是 | **你自己的 agent id** | +| `endpoint` | `protocol='http'` 时必填 | API 基础 URL | +| `riskLevel` | 推荐 | `low` / `medium` / `high` / `critical` | +| `auth` | 服务需要鉴权时 | `{ type, secretRef }` — 见下文 | +| `operations` | 推荐 | 操作清单,会被 per-service Skill 渲染成示例 | +| `capabilities` | 可选 | 能力标签 | + +### Step 2 — 诚实地选择 `riskLevel` + +`riskLevel` 决定 **未来调用** 该服务时是否触发审批闸门: + +- `low` — 只读数据,调用无副作用(如公开天气 API) +- `medium` — 大多数 API 的默认值;同一会话首次调用可能提示 +- `high` — 涉及金钱、发邮件、修改用户数据等的服务 +- `critical` — 可能造成不可逆后果;**每次** 调用都要人类审批 + +**不确定时倾向于更高风险等级。** 低估比高估更糟。 + +### Step 3 — 用 `secretRef` 引用凭据,**不要** 内联明文 + +**不要把 API key/token 写进目录条目。** 目录是全局可见的,Store UI 任何人都能查看, +未来还可能被审计。正确做法: + +```jsonc +{ + "auth": { + "type": "bearer", + "secretRef": "secrets/api-keys/acme" // 指针,不是真正的 key + } +} +``` + +`HttpRequest` 在调用时解引用 `secretRef`。如果对应 secret 还不存在,请通过 +用户自己的凭据管理流程让他/她填好 —— 不要在聊天里收明文。 + +### Step 4 — 调用注册 API + +用 `HttpRequest` 工具 POST 到本机 Agent Service: + +```yaml +tool: HttpRequest +parameters: + url: http://127.0.0.1:/api/registry/agent-services + method: POST + body: + id: acme-search-api + name: "Acme 搜索 API" + description: "对 Acme 产品库做全文搜索" + protocol: http + endpoint: https://api.acme.example/search + tags: ["search", "products"] + registeredBy: "" + riskLevel: medium + auth: + type: bearer + secretRef: secrets/api-keys/acme + operations: + - name: search + method: GET + path: /v1/items + description: "按 query 搜索商品" + - name: getDetail + method: GET + path: /v1/items/{id} + description: "按 id 获取单个商品" +``` + +(Agent Service 端口由运行时提供;不确定如何获取时用 `request-help` 技能问。) + +### Step 5 — 等待人类批准 + +该端点会触发 **service-approval** 请求,HTTP 调用会一直阻塞,直到用户在 +Store UI 批准或拒绝。 + +- **批准** → 条目写入 `~/.desirecore/config/registry-agent-services.json`, + 状态为 `reviewStatus: 'pending'`。pending 期间 **只有你**(注册者)能调用。 +- **拒绝** → API 返回 403;不要重试,问用户下一步怎么办。 + +人类后续可以在 Store UI 把条目从 `pending` **提升(promote)** 为 `approved`。 +提升后该服务对所有 Agent 可调,且会触发 `service-skill-generator` 生成 +`~/.desirecore/skills/svc-/SKILL.md`,里头有基于 `operations` 的示例。 + +### Step 6 — 不要重复注册 + +如果 `POST /api/registry/agent-services` 返回 `409 Conflict`,说明该服务已存在。 +除非用户明确要求注册一个独立变种,否则不要换个 id 静默注册 —— 偷偷影子覆盖 +已有服务是治理失败。 + +## 常见失败模式 + +- **SSRF 拦截**:注册 API 拒绝私网地址(10.x / 172.16-31.x / 192.168.x / 169.254.x), + 本机环回除外。公网 IP 与 DNS 域名允许。 +- **缺 `registeredBy`**:API 返回 400。必须带上你自己的 agent id —— 不允许匿名注册。 +- **审批超时**:broker 等待用户太久会超时,按 `rejected` 处理。 diff --git a/skills/using-services/SKILL.md b/skills/using-services/SKILL.md new file mode 100644 index 0000000..ef2952b --- /dev/null +++ b/skills/using-services/SKILL.md @@ -0,0 +1,184 @@ +--- +name: using-services +description: >- + Discover and invoke HTTP/MCP services already registered in the global + catalog. Use when the user asks the Agent to call an API, search for an + existing service, or query a backend that was registered via the + registering-services skill. 调用某个 API、查找已有服务、访问已注册的后端服务时使用。 +version: 1.0.0 +type: meta +risk_level: low +status: enabled +disable-model-invocation: true +tags: + - service + - catalog + - http + - mcp + - meta +metadata: + author: desirecore + updated_at: '2026-05-28' + i18n: + default_locale: en-US + source_locale: zh-CN + locales: + - zh-CN + - en-US + zh-CN: + name: 使用服务 + short_desc: 发现并调用全局目录中已注册的服务 + description: >- + 发现并调用全局应用与服务目录中已经注册过的 HTTP/MCP 服务。Use when 用户让 Agent 调用某个 API、查找已有服务,或访问通过 registering-services 注册的后端。 + body: ./SKILL.zh-CN.md + translated_by: human + en-US: + name: Using Services + short_desc: Discover and invoke registered services from the catalog + description: >- + Discover and invoke HTTP/MCP services already registered in the global catalog. Use when the user asks the Agent to call an API, search for an existing service, or query a backend that was registered via the registering-services skill. + body: ./SKILL.md + translated_by: human +market: + category: productivity + maintainer: + name: DesireCore Official + verified: true + channel: latest +--- + +# using-services Skill + +## L0: One-line Summary + +Teach the Agent how to look up and call services from the global +"Apps & Services" catalog. + +## L1: Overview + +The "Apps & Services" catalog stores all registered HTTP/MCP services. This +meta-skill is your manual for **finding** the right service and **invoking** +it correctly. Each non-trivial registered service also has its own +`svc-` Skill auto-generated from its operations — prefer that when it +exists; this meta-skill is the fallback for ad-hoc discovery. + +### When to use + +- The user asks you to do something that might already have a registered service + (e.g. "search the product database", "send a notification") +- You see `svc-` Skill in your available skills list — activate it directly +- You need to call an HTTP API and want to check if it's been registered (to + benefit from governance, credential injection, and audit) + +### When NOT to use + +- The user gives you a one-off URL to fetch — use `HttpRequest` directly +- You already have the per-service `svc-` Skill activated — follow it + instead, it's more specific + +## L2: How to discover and call + +### Step 1 — List the catalog + +Fetch the registry: + +```yaml +tool: HttpRequest +parameters: + url: http://127.0.0.1:/api/registry/services + method: GET +``` + +Response shape (excerpt): + +```json +{ + "data": { + "services": [ + { + "id": "acme-search-api", + "name": "Acme Search API", + "protocol": "http", + "endpoint": "https://api.acme.example/search", + "tags": ["search", "products"], + "status": "online", + "origin": "agent", + "reviewStatus": "approved", + "riskLevel": "medium", + "operations": [...] + } + ], + "total": 1, + "source": "official" + } +} +``` + +### Step 2 — Pick a candidate + +Filter by `tags`, `protocol`, `name`. Important checks **before** invoking: + +- `status === 'online'` → safe to call +- `status === 'offline'` / `'error'` → tell the user the service is down, + **don't** retry blindly +- `status === 'degraded'` → degrade gracefully, mention it to the user +- `reviewStatus === 'pending'` (only `origin='agent'`) → you can only call it + if `registeredBy` is you; otherwise ask the user to promote it +- `riskLevel === 'critical'` → expect a human approval prompt on every call + +### Step 3 — Build the request (HTTP services) + +If the service has `operations`, prefer them — they define stable contract +points. Build the URL as ``. + +```yaml +tool: HttpRequest +parameters: + url: https://api.acme.example/search/v1/items?q=widget + method: GET + headers: + Authorization: "Bearer ${secrets/api-keys/acme}" # resolved at call time +``` + +If the service declares `auth.secretRef`, **do not** prompt the user for the +secret value during chat. The `HttpRequest` tool resolves it automatically. + +### Step 4 — Build the request (MCP services) + +MCP services aren't called via `HttpRequest` — they are tools exposed through +the Agent's `mcp_servers` config: + +1. If you haven't added the MCP service to your Agent yet, POST to + `http://127.0.0.1:/api/agents//mcp-servers` with `{ serverId: '', config: }` +2. Next query, MCP discovery will auto-expose tools from the server +3. Call the tools by their MCP-declared names directly + +### Step 5 — Handle the response + +- 2xx → parse and use +- 4xx → likely a client error (bad params, missing auth); fix the request, + then retry once; if it still fails, report to the user +- 5xx → server-side problem, report `status` of the service back so the user + knows +- **Service-approval rejected** → response will contain `"decision":"rejected"`; + do not retry, ask the user how to proceed + +### Step 6 — Don't fall through to raw URL fetching + +If the catalog has a service for what you need, **use it**. Don't bypass +governance by calling an undeclared URL directly — `HttpRequest` will still +work, but you lose: + +- Approval gating for high-risk operations +- Credential injection (you'd need to ask the user for keys yourself) +- Audit trail and `lastUsed` tracking +- Other Agents being able to reuse your call patterns + +## Failure modes + +- **Catalog read fails**: just fall back to direct `HttpRequest` and warn the + user that governance is bypassed. +- **No matching service**: ask the user if they want to **register** a new + one — activate `registering-services` skill. +- **`status === 'offline'`**: report the situation, suggest checking the + underlying service, **don't** call anyway. diff --git a/skills/using-services/SKILL.zh-CN.md b/skills/using-services/SKILL.zh-CN.md new file mode 100644 index 0000000..eae4f91 --- /dev/null +++ b/skills/using-services/SKILL.zh-CN.md @@ -0,0 +1,122 @@ + + +# 使用服务(using-services) + +## L0:一句话总结 + +教会 Agent 如何从全局"应用与服务目录"里查找并正确调用服务。 + +## L1:概述 + +"应用与服务目录"存放所有已注册的 HTTP/MCP 服务。本元技能是你的 **使用手册**: +帮你 **找到** 合适的服务、**正确** 调用它。每个非平凡的注册服务还会自动生成 +专属 `svc-` Skill —— 优先用专属技能;本元技能是临时发现的兜底。 + +### 何时使用 + +- 用户让你做某件事,目录里可能有现成服务(如"搜产品库"、"发通知") +- 你看到可用技能里有 `svc-` —— 直接激活它 +- 你打算调用一个 HTTP API,想先查目录,借力治理、凭据注入和审计 + +### 何时不要用 + +- 用户给了一次性 URL —— 直接 `HttpRequest` 即可 +- 你已激活了 `svc-` 专属 Skill —— 跟着它走,更具体 + +## L2:如何发现并调用 + +### Step 1 — 列目录 + +拉取注册表: + +```yaml +tool: HttpRequest +parameters: + url: http://127.0.0.1:/api/registry/services + method: GET +``` + +响应(节选): + +```json +{ + "data": { + "services": [ + { + "id": "acme-search-api", + "name": "Acme 搜索 API", + "protocol": "http", + "endpoint": "https://api.acme.example/search", + "tags": ["search", "products"], + "status": "online", + "origin": "agent", + "reviewStatus": "approved", + "riskLevel": "medium", + "operations": [...] + } + ], + "total": 1, + "source": "official" + } +} +``` + +### Step 2 — 选候选 + +按 `tags`、`protocol`、`name` 过滤。调用 **前** 必须检查: + +- `status === 'online'` → 可以调 +- `status === 'offline'` / `'error'` → 告诉用户服务下线,**别** 盲目重试 +- `status === 'degraded'` → 降级使用,告诉用户 +- `reviewStatus === 'pending'`(仅 `origin='agent'`)→ 只有当 `registeredBy` + 就是你自己时才能调;否则请用户在 Store UI 提升后再用 +- `riskLevel === 'critical'` → 每次调用都会触发人类审批 + +### Step 3 — 构造请求(HTTP 服务) + +如果服务声明了 `operations`,优先用 —— 它们是稳定契约点。URL 拼成 +``。 + +```yaml +tool: HttpRequest +parameters: + url: https://api.acme.example/search/v1/items?q=widget + method: GET + headers: + Authorization: "Bearer ${secrets/api-keys/acme}" # 调用时解引用 +``` + +如果服务带 `auth.secretRef`,**不要** 在聊天里向用户索要明文凭据。 +`HttpRequest` 工具会自动解引用。 + +### Step 4 — 构造请求(MCP 服务) + +MCP 服务不走 `HttpRequest`,它通过 Agent 的 `mcp_servers` 配置暴露成工具: + +1. 若你的 Agent 还没接入该 MCP,POST `http://127.0.0.1:/api/agents//mcp-servers` + 传 `{ serverId: '', config: }` +2. 下轮 query 时 MCP discovery 会自动暴露该服务器的工具 +3. 直接用 MCP 工具名调用即可 + +### Step 5 — 处理响应 + +- 2xx → 解析使用 +- 4xx → 多半是客户端错(参数错、缺鉴权);修好后可重试一次,仍失败就告诉用户 +- 5xx → 服务端问题,把目录里的 `status` 一并告诉用户 +- **service-approval 拒绝** → 响应里会有 `"decision":"rejected"`;不要重试,问用户怎么办 + +### Step 6 — 不要绕开目录 + +如果目录里有该服务,**就用目录**。直接调未声明的 URL 虽然 `HttpRequest` +也能成功,但你会失去: + +- 高风险操作的审批闸门 +- 凭据注入(你得自己问用户要 key) +- 审计追踪与 `lastUsed` 统计 +- 其他 Agent 复用你的调用模式 + +## 常见失败模式 + +- **目录读取失败**:降级直接 `HttpRequest`,并告诉用户已绕开治理。 +- **没匹配上**:问用户要不要 **注册** 一个新的 —— 激活 `registering-services`。 +- **`status === 'offline'`**:汇报情况,建议检查底层服务,**不要** 强行调用。