From 0088eb39fb2351d087e74baebb5269aefc47b8cf Mon Sep 17 00:00:00 2001 From: Kevin Cui Date: Sat, 4 Jul 2026 11:09:51 -0400 Subject: [PATCH] docs(connector): add self-hosted connector integration guide Document how to point the `oo` CLI at a self-hosted connector server in both English and Simplified Chinese, distilled from the self-hosted connector feature (#291) and its follow-up cleanup (#292). The command reference in `docs/commands.md` only records the per-command CLI contract, so there was no single place that explained the end-to-end onboarding flow or the HTTP contract a connector server must expose. The new guides cover both audiences: operators wiring the CLI to a server (`oo connector login`/`logout`, runtime tokens and the `/access` page, the `OO_CONNECTOR_URL` > `OO_API_KEY` > `connector.toml` > account routing precedence, and the OOMOL vs self-hosted feature differences), and server implementers (the `/v1/*` endpoints, health envelope, Bearer auth model, and response shapes). Link both guides from `README.md` and `README-ZH_CN.md` for discovery. Signed-off-by: Kevin Cui --- README-ZH_CN.md | 1 + README.md | 1 + docs/self-hosted-connector.md | 362 ++++++++++++++++++++++++++++ docs/self-hosted-connector.zh-CN.md | 327 +++++++++++++++++++++++++ 4 files changed, 691 insertions(+) create mode 100644 docs/self-hosted-connector.md create mode 100644 docs/self-hosted-connector.zh-CN.md diff --git a/README-ZH_CN.md b/README-ZH_CN.md index c7a9b33..ca975d8 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -91,6 +91,7 @@ hostname、IP 地址、真实 OOMOL 账号 ID 或账号名。Telemetry 控制方 - [OOMOL Console — Connections](https://console.oomol.com/connections) - [命令参考](./docs/commands.zh-CN.md) +- [自部署 Connector 接入指南](./docs/self-hosted-connector.zh-CN.md) - [Contributing](./CONTRIBUTING.md) - [Privacy](./PRIVACY-ZH_CN.md) diff --git a/README.md b/README.md index 35013e0..e3ebcea 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ documented in [PRIVACY.md](./PRIVACY.md). - [OOMOL Console — Connections](https://console.oomol.com/connections) - [Command reference](./docs/commands.md) +- [Self-hosted connector integration](./docs/self-hosted-connector.md) - [Contributing](./CONTRIBUTING.md) - [Privacy](./PRIVACY.md) diff --git a/docs/self-hosted-connector.md b/docs/self-hosted-connector.md new file mode 100644 index 0000000..9df4fb1 --- /dev/null +++ b/docs/self-hosted-connector.md @@ -0,0 +1,362 @@ +# Self-Hosted Connector Integration Guide + +[English](./self-hosted-connector.md) | [简体中文](./self-hosted-connector.zh-CN.md) + +Command reference: [commands.md](./commands.md) + +This guide explains how to point the `oo` CLI at a connector server you run +yourself instead of the OOMOL-hosted connector, and what HTTP contract such a +server must expose. It covers two audiences: + +- **Operators** who want their connector commands to talk to a self-hosted + server (the "Getting started", "Runtime tokens", "Routing", and + "Troubleshooting" sections). +- **Server implementers** who want to build a server the CLI can talk to (the + "Server contract" section). + +## Overview + +A self-hosted connector is a **capability override, not an account**. When one +is configured, the connector-family commands route their requests to your +server instead of the OOMOL-hosted connector service. Everything else about the +CLI — your OOMOL account, billing, skills — is unchanged. + +Key properties: + +- The configuration lives in `connector.toml`, stored **separately from** + `auth.toml`. Logging in to a self-hosted connector never touches your OOMOL + account, and vice versa. +- The self-hosted runtime has **no account concept**. Authentication, when + enabled, is a single runtime API token rather than per-user login. +- Only connector-family commands are affected. Commands that need an OOMOL + account (file upload, LLM, skills publishing, etc.) keep requiring + `oo auth login`. + +The following commands route to the configured self-hosted connector: + +- `oo connector search` +- `oo connector schema` +- `oo connector run` +- `oo connector apps` +- `oo connector proxy` +- `oo search` (top-level alias of `oo connector search`) + +## Prerequisites + +1. A running connector server reachable over `http://` or `https://` that + implements the [Server contract](#server-contract) below. During local + development this is typically something like `http://localhost:3000`. +2. The server's base URL. It may include a path prefix (for example when the + server sits behind a reverse proxy at `https://example.com/oo-connector`). +3. Optionally, a **runtime token** if the server has authentication enabled. + Tokens are created on the server's `/access` page. + +## Getting started + +Connect to a server that has authentication disabled: + +```bash +oo connector login http://localhost:3000 +``` + +Connect to a server that requires a runtime token: + +```bash +oo connector login https://connector.example.com --token +``` + +On success the CLI prints the connected server URL, reports whether the token +was verified, and points you to `/access` for managing runtime tokens: + +```text +✓ Connected to the self-hosted connector at https://connector.example.com +The token was accepted by the server. +Manage runtime tokens at https://connector.example.com/access +``` + +After a successful login, every connector-family command uses this server: + +```bash +oo connector search "send an email" +oo connector schema "gmail.send_email" +oo connector run gmail --action send_email --data '@payload.json' +oo connector apps gmail +``` + +When you are done, switch connector commands back to your OOMOL account: + +```bash +oo connector logout +``` + +### What `oo connector login` validates + +Before saving anything, `login` probes the server's health endpoint +(`GET /v1/health`, with a 10-second timeout) so a misconfigured URL fails +immediately instead of surfacing later during a real command: + +- A non-`http(s)` URL, or a URL that carries a query string, fragment, or + embedded `user:pass@` credentials, is rejected with exit code `2` before any + request is made. +- An empty token, or one containing whitespace or control characters, is + rejected with exit code `2`. +- An unreachable server, an HTTP `401`, or a response that is not a valid + connector health payload exits `1`. The `401` error includes a hint to create + a runtime token at `/access`. + +Only after the health check passes is the configuration written to +`connector.toml`. + +## Runtime tokens + +If your server enforces authentication, pass a token created on the server's +`/access` page: + +```bash +oo connector login https://connector.example.com --token +``` + +The CLI sends the token as an `Authorization: Bearer ` header on every +connector request. + +Token verification is best-effort and honest about what it can prove: + +- **Token accepted.** The authenticated health check succeeded and a + header-less probe was rejected, so the token is genuinely required and valid. + Output: `The token was accepted by the server.` +- **Token could not be verified.** The server also accepts unauthenticated + requests, so a `200` does not prove the token is valid. The configuration is + still saved and a warning is printed. +- **No token configured.** Output notes that if the server enables tokens + later, you should create one at `/access` and log in again. + +## Routing precedence + +When a connector-family command runs, it resolves its target server with this +precedence (first match wins): + +| Priority | Source | Target | +| --- | --- | --- | +| 1 | `OO_CONNECTOR_URL` (+ optional `OO_CONNECTOR_TOKEN`) | Self-hosted server from the environment | +| 2 | `OO_API_KEY` (+ optional `OO_ENDPOINT`) | OOMOL-hosted connector for that key | +| 3 | `connector.toml` (saved by `oo connector login`) | Persisted self-hosted server | +| 4 | The active OOMOL account | OOMOL-hosted connector for that account | + +Two consequences worth remembering: + +- `OO_API_KEY` outranks a saved `connector.toml`. Setting an explicit hosted + credential always routes connector commands to the OOMOL service, so a + persisted self-hosted configuration never hijacks an explicit hosted key. + Only `OO_CONNECTOR_URL` outranks `OO_API_KEY`. +- If none of the above resolve and the command needs a target, it falls back to + the active account and raises the standard "login required" error. + +### Environment overrides (headless / CI) + +`OO_CONNECTOR_URL` and `OO_CONNECTOR_TOKEN` point connector commands at a +self-hosted server **without touching `connector.toml`**. This mirrors how +`OO_API_KEY` works for the OOMOL services and is the recommended approach for +containers and CI: + +```bash +export OO_CONNECTOR_URL="https://connector.example.com" +export OO_CONNECTOR_TOKEN="" # optional +oo connector run gmail --action send_email --data '@payload.json' +``` + +Notes: + +- `OO_CONNECTOR_TOKEN` is ignored when `OO_CONNECTOR_URL` is not set. +- The environment override does not modify or remove any saved + `connector.toml`; it simply takes precedence for the current process. +- `oo connector logout` removes the saved configuration only. It does **not** + clear `OO_CONNECTOR_URL`; unset that variable yourself to fall back. + +## Feature differences vs the OOMOL-hosted connector + +A self-hosted runtime exposes a smaller surface than the OOMOL service. The CLI +adapts as follows: + +- **Organization identity is not supported.** `--organization` / `--org` is + rejected with exit code `2` on `oo connector run` and `oo connector proxy`, + and any configured `identity.organization` default is ignored. `--personal` + is accepted (it is already the effective behavior). +- **Async lifecycle waiting is unavailable.** `--wait` and `--wait-result` fail + with the existing "unsupported" errors because the self-hosted runtime does + not expose the async result-lifecycle contract. +- **Proxy depends on server support.** `oo connector proxy` works only if your + server implements the proxy endpoint; the reference open-source runtime + currently returns an error for it. + +Commands that require an OOMOL account continue to require one regardless of the +self-hosted configuration, including `oo file upload`, the `oo llm` commands, +`oo variables`, and the `oo skills` search/install/publish/sync commands. When +they fail, run `oo auth login`. + +## Inspecting the configuration + +`oo auth status` reports the active self-hosted connector alongside your OOMOL +accounts. In text mode it adds a block with the server URL, whether a token is +configured (the token value itself is never printed), and the configuration +source: + +```text +✓ Self-hosted connector: https://connector.example.com + - Token configured: yes + - Source: file +``` + +In JSON mode (`oo auth status --json`), the payload carries an optional +top-level `connector` object: + +```json +{ + "connector": { + "url": "https://connector.example.com", + "tokenConfigured": true, + "source": "file" + } +} +``` + +- `source` is `env` when the configuration comes from `OO_CONNECTOR_URL`, or + `file` when it comes from `connector.toml`. +- The block is present whenever a self-hosted connector is configured, even + when `status` is not `logged-in` — this is how an agent detects + "self-hosted-only" mode. +- Remember that when `OO_API_KEY` is set, connector commands route to the OOMOL + service even if a `source: "file"` configuration exists (only + `OO_CONNECTOR_URL` outranks `OO_API_KEY`). + +## Storage: `connector.toml` + +The saved configuration is a small TOML file in the configuration root +directory: + +- macOS: `~/Library/Application Support/oo/connector.toml` +- Linux: `${XDG_CONFIG_HOME:-~/.config}/oo/connector.toml` +- Windows: `%APPDATA%\oo\connector.toml` + +`OO_CONFIG_DIR` overrides the configuration root directly. The file exists only +after `oo connector login`; an untouched installation has none. Its contents: + +```toml +[self_hosted] +url = "https://connector.example.com" +token = "" # present only when a token was configured +``` + +`oo connector logout` removes the `[self_hosted]` block. A corrupt +`connector.toml` is cleared by logout as well, so logout always leaves the +configuration removed. + +## Server contract + +To be usable as a self-hosted connector, your server must implement the +following HTTP endpoints. All paths are appended to the configured base URL by +string concatenation, so any path prefix in the base URL (for example +`https://example.com/oo-connector`) is preserved. + +| Method | Path | Used by | Purpose | +| --- | --- | --- | --- | +| `GET` | `/v1/health` | `oo connector login` | Health check for login validation | +| `GET` | `/v1/actions/search?q=` | `oo connector search`, `oo search` | Semantic action search | +| `GET` | `/v1/actions/.` | `oo connector schema` | Action metadata / schema | +| `POST` | `/v1/actions/.` | `oo connector run` | Run one action | +| `GET` | `/v1/apps/services/` | `oo connector apps` | List connected apps for a service | +| `POST` | `/v1/proxy/` | `oo connector proxy` | Proxy a provider API request | + +Service and action names are URL-encoded; the run/schema path uses the +`.` form (for example `/v1/actions/gmail.send_email`). + +### Authentication + +- If a runtime token is configured (via `--token`, `connector.toml`, or + `OO_CONNECTOR_TOKEN`), every request carries an + `Authorization: Bearer ` header. Compare it exactly. +- A server with authentication disabled should accept requests that carry no + `Authorization` header. +- Return HTTP `401` to signal that a token is required. `oo connector login` + turns a `401` into a message pointing the user to `/access`. + +### Health response (`GET /v1/health`) + +Return HTTP `200` with a JSON envelope whose `success` is `true` and whose +`data.ok` is `true`. Additional envelope fields are ignored, so you can extend +it freely: + +```json +{ "success": true, "data": { "ok": true } } +``` + +`oo connector login` treats any of the following as failure: a non-`200` +status, a non-JSON body, or an envelope where `success` or `data.ok` is not +`true`. + +### Search response (`GET /v1/actions/search`) + +Return a JSON object with a `data` array. Each entry describes one action; the +CLI reads `service`, `name`, `description`, `authenticated`, `inputSchema`, and +`outputSchema`: + +```json +{ + "data": [ + { + "service": "gmail", + "name": "send_email", + "description": "Send an email", + "authenticated": true, + "inputSchema": { "...": "..." }, + "outputSchema": { "...": "..." } + } + ] +} +``` + +`authenticated` reflects whether the service already has a connected, +authorized app on the server. The CLI surfaces it directly in search output and +warms its local schema cache from the returned `inputSchema` / `outputSchema`. + +### Metadata response (`GET /v1/actions/.`) + +Return the single action's contract under a top-level `data` object, with the +same `service`, `name`, `description`, `inputSchema`, and `outputSchema` fields. + +### Run request (`POST /v1/actions/.`) + +The CLI sends `Content-Type: application/json` and a body of the form: + +```json +{ "input": { "...": "action input data" } } +``` + +A successful response uses the stable `{ data, meta: { executionId } }` shape. +On failure, include a `message` and an `errorCode` in the body when possible; +the CLI surfaces both in its error output. + +### Apps and proxy + +- `GET /v1/apps/services/` returns the connected apps for a service, + used by `oo connector apps`. +- `POST /v1/proxy/` proxies a provider API request, used by + `oo connector proxy`. Implement it only if you support proxy execution. + +### The `/access` page + +`/access` is a web page (not an API the CLI calls) where users create +and manage runtime tokens. The CLI references it in login output and in the +`401` error hint, so hosting a page there makes token management discoverable. + +## Troubleshooting + +| Symptom | Likely cause and fix | +| --- | --- | +| `The connector URL ... is not a valid http(s) URL.` (exit 2) | The URL is not `http(s)`, or it carries a query, fragment, or embedded credentials. Pass a clean origin such as `http://localhost:3000`. | +| `The connector token must not be empty or contain whitespace or control characters.` (exit 2) | The `--token` value is empty or contains whitespace/control characters. | +| `Could not reach the connector server at ...` (exit 1) | The server is unreachable during login. Confirm it is running and the URL is correct. | +| `The connector server rejected the request (HTTP 401).` (exit 1) | The server requires a token. Create one at `/access` and pass it with `--token`. | +| `The server at ... did not return a connector health response.` (exit 1) | The URL points at something that is not a connector server, or `/v1/health` does not return the expected envelope. | +| `Could not reach the self-hosted connector at ...` (during a command) | The saved server is down. Start it, or run `oo connector login` to reconfigure. This is not a sandbox or permission problem — do not retry with elevated permissions. | +| `The --organization option is not supported by a self-hosted connector.` (exit 2) | Self-hosted runtimes have no organization identity. Drop `--organization` / `--org`, or use `--personal`. | +| A command needs an OOMOL account | Non-connector features (file upload, LLM, skills) still require `oo auth login`. | diff --git a/docs/self-hosted-connector.zh-CN.md b/docs/self-hosted-connector.zh-CN.md new file mode 100644 index 0000000..7e6fc2d --- /dev/null +++ b/docs/self-hosted-connector.zh-CN.md @@ -0,0 +1,327 @@ +# 自部署 Connector 接入指南 + +[English](./self-hosted-connector.md) | [简体中文](./self-hosted-connector.zh-CN.md) + +命令参考见 [commands.zh-CN.md](./commands.zh-CN.md) + +本指南介绍如何让 `oo` CLI 连接到你自行部署的 Connector 服务(而非 OOMOL 托管的 +Connector),以及这样的服务需要暴露怎样的 HTTP 契约。文档面向两类读者: + +- **使用者**:希望让 connector 命令请求自部署服务(见「快速开始」「Runtime + 令牌」「路由优先级」「排障」等章节)。 +- **服务实现者**:希望搭建一个 CLI 能对接的服务(见「服务端契约」章节)。 + +## 概览 + +自部署 Connector 是一种**能力覆盖,而非账号**。配置后,connector 相关命令会将请求 +路由到你的服务,而不是 OOMOL 托管的 Connector 服务。CLI 的其他部分——你的 OOMOL +账号、计费、skills——都不受影响。 + +关键特性: + +- 配置保存在 `connector.toml` 中,与 `auth.toml` **相互独立**。登录自部署 + Connector 不会改动你的 OOMOL 账号,反之亦然。 +- 自部署运行时**没有账号概念**。启用鉴权时,使用的是单一的 Runtime API 令牌, + 而不是逐用户登录。 +- 只有 connector 相关命令会被影响。需要 OOMOL 账号的命令(文件上传、LLM、skills + 发布等)仍需 `oo auth login`。 + +以下命令会路由到已配置的自部署 Connector: + +- `oo connector search` +- `oo connector schema` +- `oo connector run` +- `oo connector apps` +- `oo connector proxy` +- `oo search`(`oo connector search` 的顶层别名) + +## 前置条件 + +1. 一个可通过 `http://` 或 `https://` 访问、并实现下文[服务端契约](#服务端契约)的 + Connector 服务。本地开发时通常形如 `http://localhost:3000`。 +2. 服务的基础 URL。它可以带路径前缀(例如服务位于反向代理后的 + `https://example.com/oo-connector`)。 +3. 若服务启用了鉴权,还需要一个 **Runtime 令牌**。令牌在服务的 `/access` 页面 + 创建。 + +## 快速开始 + +连接一个未启用鉴权的服务: + +```bash +oo connector login http://localhost:3000 +``` + +连接一个需要 Runtime 令牌的服务: + +```bash +oo connector login https://connector.example.com --token +``` + +成功后,CLI 会打印已连接的服务 URL、说明令牌是否通过验证,并指向 `/access` +以管理 Runtime 令牌: + +```text +✓ 已连接自部署 Connector:https://connector.example.com +令牌已通过服务验证。 +可在 https://connector.example.com/access 管理 Runtime Token。 +``` + +登录成功后,所有 connector 相关命令都会使用该服务: + +```bash +oo connector search "发送邮件" +oo connector schema "gmail.send_email" +oo connector run gmail --action send_email --data '@payload.json' +oo connector apps gmail +``` + +完成后,将 connector 命令切回你的 OOMOL 账号: + +```bash +oo connector logout +``` + +### `oo connector login` 的校验流程 + +在写入任何配置之前,`login` 会探测服务的健康检查端点(`GET /v1/health`,超时 +10 秒),使配置错误的 URL 立即失败,而不是等到真正执行命令时才暴露: + +- 非 `http(s)` 的 URL,或带有查询字符串、片段(fragment)、内嵌 + `user:pass@` 凭据的 URL,会在发出任何请求前以退出码 `2` 被拒绝。 +- 空令牌,或包含空白、控制字符的令牌,会以退出码 `2` 被拒绝。 +- 服务不可达、返回 HTTP `401`、或返回的响应不是有效的 connector 健康响应,均以 + 退出码 `1` 失败。`401` 错误会附带提示,引导你在 `/access` 创建 Runtime + 令牌。 + +只有健康检查通过后,配置才会写入 `connector.toml`。 + +## Runtime 令牌 + +如果你的服务强制鉴权,请传入在服务 `/access` 页面创建的令牌: + +```bash +oo connector login https://connector.example.com --token +``` + +CLI 会在每个 connector 请求上以 `Authorization: Bearer ` 头发送该令牌。 + +令牌验证是尽力而为的,并且会如实说明能证明什么: + +- **令牌已被接受。** 带鉴权的健康检查成功,且不带头部的探测被拒绝,说明令牌确实 + 是必需且有效的。输出:`令牌已通过服务验证。` +- **令牌无法验证。** 服务同时也接受未鉴权请求,因此 `200` 不能证明令牌有效。 + 配置仍会保存,并打印一条警告。 +- **未配置令牌。** 输出会提示:若服务日后启用令牌,请在 `/access` 创建一个 + 并重新登录。 + +## 路由优先级 + +当 connector 相关命令运行时,按以下优先级解析目标服务(先命中者生效): + +| 优先级 | 来源 | 目标 | +| --- | --- | --- | +| 1 | `OO_CONNECTOR_URL`(及可选的 `OO_CONNECTOR_TOKEN`) | 环境变量指定的自部署服务 | +| 2 | `OO_API_KEY`(及可选的 `OO_ENDPOINT`) | 该 key 对应的 OOMOL 托管 Connector | +| 3 | `connector.toml`(`oo connector login` 保存的配置) | 已持久化的自部署服务 | +| 4 | 当前激活的 OOMOL 账号 | 该账号对应的 OOMOL 托管 Connector | + +两个需要记住的结论: + +- `OO_API_KEY` 的优先级高于已保存的 `connector.toml`。设置显式的托管凭据总会让 + connector 命令路由到 OOMOL 服务,因此已持久化的自部署配置永远不会劫持显式的 + 托管 key。只有 `OO_CONNECTOR_URL` 的优先级高于 `OO_API_KEY`。 +- 若以上来源都无法解析、而命令又需要目标,则回退到当前激活账号,并抛出标准的 + 「需要登录」错误。 + +### 环境变量覆盖(无头 / CI) + +`OO_CONNECTOR_URL` 与 `OO_CONNECTOR_TOKEN` 可以在**不改动 `connector.toml`** 的 +前提下,将 connector 命令指向自部署服务。这与 `OO_API_KEY` 之于 OOMOL 服务的机制 +一致,是容器和 CI 场景的推荐做法: + +```bash +export OO_CONNECTOR_URL="https://connector.example.com" +export OO_CONNECTOR_TOKEN="" # 可选 +oo connector run gmail --action send_email --data '@payload.json' +``` + +注意: + +- 未设置 `OO_CONNECTOR_URL` 时,`OO_CONNECTOR_TOKEN` 会被忽略。 +- 环境变量覆盖不会修改或删除任何已保存的 `connector.toml`,只是在当前进程中 + 优先生效。 +- `oo connector logout` 只移除已保存的配置,**不会**清除 `OO_CONNECTOR_URL`; + 需要回退时请自行 unset 该变量。 + +## 与 OOMOL 托管 Connector 的功能差异 + +自部署运行时暴露的能力比 OOMOL 服务更小,CLI 会做如下适配: + +- **不支持组织身份。** `oo connector run` 与 `oo connector proxy` 上的 + `--organization` / `--org` 会以退出码 `2` 被拒绝,任何已配置的 + `identity.organization` 默认值都会被忽略;`--personal` 可以使用(它本就是实际 + 行为)。 +- **无法等待异步生命周期。** `--wait` 与 `--wait-result` 会以既有的「不支持」 + 错误失败,因为自部署运行时未暴露异步结果生命周期契约。 +- **Proxy 取决于服务支持。** 只有当你的服务实现了 proxy 端点时, + `oo connector proxy` 才可用;参考用的开源运行时目前对其返回错误。 + +无论是否配置了自部署 Connector,需要 OOMOL 账号的命令仍然需要账号,包括 +`oo file upload`、`oo llm` 系列命令、`oo variables`,以及 `oo skills` 的 +search/install/publish/sync 命令。这些命令失败时,请运行 `oo auth login`。 + +## 查看当前配置 + +`oo auth status` 会在展示 OOMOL 账号的同时报告当前生效的自部署 Connector。文本模式 +下会增加一个区块,显示服务 URL、是否已配置令牌(令牌值本身永不打印)以及配置来源: + +```text +✓ 自部署 Connector:https://connector.example.com + - 已配置令牌: 是 + - 来源: file +``` + +JSON 模式(`oo auth status --json`)下,输出会带一个可选的顶层 `connector` 对象: + +```json +{ + "connector": { + "url": "https://connector.example.com", + "tokenConfigured": true, + "source": "file" + } +} +``` + +- 当配置来自 `OO_CONNECTOR_URL` 时,`source` 为 `env`;来自 `connector.toml` 时 + 为 `file`。 +- 只要配置了自部署 Connector,该区块就会出现,即使 `status` 不是 `logged-in`—— + 这正是 agent 判断「仅自部署」模式的依据。 +- 请记住:当设置了 `OO_API_KEY` 时,即便存在 `source: "file"` 的配置,connector + 命令仍会路由到 OOMOL 服务(只有 `OO_CONNECTOR_URL` 的优先级高于 + `OO_API_KEY`)。 + +## 存储:`connector.toml` + +保存的配置是位于配置根目录下的一个小型 TOML 文件: + +- macOS:`~/Library/Application Support/oo/connector.toml` +- Linux:`${XDG_CONFIG_HOME:-~/.config}/oo/connector.toml` +- Windows:`%APPDATA%\oo\connector.toml` + +`OO_CONFIG_DIR` 会直接覆盖配置根目录。该文件仅在执行 `oo connector login` 后才存在; +全新的安装不会有它。文件内容: + +```toml +[self_hosted] +url = "https://connector.example.com" +token = "" # 仅在配置了令牌时出现 +``` + +`oo connector logout` 会移除 `[self_hosted]` 区块。损坏的 `connector.toml` 也会被 +logout 一并清除,因此 logout 总能保证配置被移除。 + +## 服务端契约 + +要作为自部署 Connector 被使用,你的服务必须实现以下 HTTP 端点。所有路径都通过字符串 +拼接追加到已配置的基础 URL 之后,因此基础 URL 中的任何路径前缀(例如 +`https://example.com/oo-connector`)都会被保留。 + +| 方法 | 路径 | 使用者 | 用途 | +| --- | --- | --- | --- | +| `GET` | `/v1/health` | `oo connector login` | 登录校验用的健康检查 | +| `GET` | `/v1/actions/search?q=` | `oo connector search`、`oo search` | 语义化动作搜索 | +| `GET` | `/v1/actions/.` | `oo connector schema` | 动作元数据 / schema | +| `POST` | `/v1/actions/.` | `oo connector run` | 执行单个动作 | +| `GET` | `/v1/apps/services/` | `oo connector apps` | 列出某服务已连接的 app | +| `POST` | `/v1/proxy/` | `oo connector proxy` | 代理一个 provider API 请求 | + +service 与 action 名称会经过 URL 编码;run/schema 路径使用 `.` +形式(例如 `/v1/actions/gmail.send_email`)。 + +### 鉴权 + +- 若配置了 Runtime 令牌(通过 `--token`、`connector.toml` 或 + `OO_CONNECTOR_TOKEN`),每个请求都会携带 `Authorization: Bearer ` 头, + 请按精确匹配校验。 +- 未启用鉴权的服务应当接受不带 `Authorization` 头的请求。 +- 返回 HTTP `401` 表示需要令牌。`oo connector login` 会把 `401` 转换为一条提示, + 引导用户前往 `/access`。 + +### 健康响应(`GET /v1/health`) + +返回 HTTP `200`,其 JSON 信封的 `success` 为 `true`、`data.ok` 为 `true`。信封中 +的其他字段会被忽略,因此你可以自由扩展: + +```json +{ "success": true, "data": { "ok": true } } +``` + +以下情形都会被 `oo connector login` 视为失败:非 `200` 状态、非 JSON 响应体,或 +`success` 与 `data.ok` 未同时为 `true` 的信封。 + +### 搜索响应(`GET /v1/actions/search`) + +返回带 `data` 数组的 JSON 对象。每一项描述一个动作,CLI 会读取 `service`、`name`、 +`description`、`authenticated`、`inputSchema` 和 `outputSchema`: + +```json +{ + "data": [ + { + "service": "gmail", + "name": "send_email", + "description": "Send an email", + "authenticated": true, + "inputSchema": { "...": "..." }, + "outputSchema": { "...": "..." } + } + ] +} +``` + +`authenticated` 表示该服务在服务端是否已有已连接、已授权的 app。CLI 会在搜索输出中 +直接呈现它,并用返回的 `inputSchema` / `outputSchema` 预热本地 schema 缓存。 + +### 元数据响应(`GET /v1/actions/.`) + +在顶层 `data` 对象下返回该动作的契约,字段与搜索相同:`service`、`name`、 +`description`、`inputSchema`、`outputSchema`。 + +### 执行请求(`POST /v1/actions/.`) + +CLI 会发送 `Content-Type: application/json`,请求体形如: + +```json +{ "input": { "...": "动作输入数据" } } +``` + +成功响应使用稳定的 `{ data, meta: { executionId } }` 结构。失败时,请尽量在响应体中 +包含 `message` 与 `errorCode`,CLI 会在错误输出中呈现二者。 + +### Apps 与 Proxy + +- `GET /v1/apps/services/` 返回某服务已连接的 app,供 `oo connector apps` + 使用。 +- `POST /v1/proxy/` 代理一个 provider API 请求,供 `oo connector proxy` + 使用。仅在你支持 proxy 执行时才需实现。 + +### `/access` 页面 + +`/access` 是一个网页(并非 CLI 调用的 API),供用户创建和管理 Runtime +令牌。CLI 会在登录输出和 `401` 错误提示中引用它,因此在该路径托管一个页面能让令牌 +管理更易被发现。 + +## 排障 + +| 现象 | 可能原因与处理 | +| --- | --- | +| `The connector URL ... is not a valid http(s) URL.`(退出码 2) | URL 不是 `http(s)`,或带有查询、片段或内嵌凭据。请传入干净的源,例如 `http://localhost:3000`。 | +| `The connector token must not be empty or contain whitespace or control characters.`(退出码 2) | `--token` 的值为空,或包含空白 / 控制字符。 | +| `Could not reach the connector server at ...`(退出码 1) | 登录时服务不可达。请确认服务已启动、URL 正确。 | +| `The connector server rejected the request (HTTP 401).`(退出码 1) | 服务需要令牌。请在 `/access` 创建令牌,并通过 `--token` 传入。 | +| `The server at ... did not return a connector health response.`(退出码 1) | URL 指向的并非 connector 服务,或 `/v1/health` 未返回预期信封。 | +| `Could not reach the self-hosted connector at ...`(执行命令时) | 已保存的服务已宕机。请启动它,或运行 `oo connector login` 重新配置。这不是沙箱或权限问题,请勿以提升权限重试。 | +| `The --organization option is not supported by a self-hosted connector.`(退出码 2) | 自部署运行时没有组织身份。请去掉 `--organization` / `--org`,或改用 `--personal`。 | +| 某命令需要 OOMOL 账号 | 非 connector 功能(文件上传、LLM、skills)仍需 `oo auth login`。 |