鉴权 (Authentication)
SDK 的每个请求都带一个 Bearer 凭据;你传哪种凭据,决定了能以谁的身份、调用哪些接口。 一共三种,先按「代码跑在哪里、代表谁」选对,再往下看细节。
三种凭据
| 凭据 | 形如 | 代表 | 从哪来 | 放在哪 |
|---|---|---|---|---|
| 个人 API Key | mysta_… | 你这个账号 | app.openhex.tech → 设置 → API Key | 只放后端 / 本地脚本 |
| 工作区 API Key | sk_… | 你的一个工作区 | 用个人 API Key 调接口签发,见工作区 API 概览 | 只放后端 |
| 会话令牌 | JWT(eyJ…) | 工作区里的某一个成员 | 你的后端用工作区 API Key 签发,见会话令牌 | 可以交给浏览器、小程序、App |
我该用哪个?
| 场景 | 凭据 |
|---|---|
| 写脚本、后端任务,调用自己的 Agent | 个人 API Key |
| 以所有者身份训练 Agent | 个人 API Key |
| 你的后端管理工作区(开通成员、发积分、签发令牌) | 工作区 API Key |
| 让你的用户在网页 / 小程序 / App 里和 Agent 对话 | 会话令牌 |
各凭据能调用的接口:
| 能力 | 个人 API Key | 工作区 API Key | 会话令牌 |
|---|---|---|---|
| 对话、附件 | ✅(以账号本人身份) | — | ✅(以成员身份) |
| 训练模式 | ✅(仅自己的 Agent) | — | — |
| 工作区 API | 仅签发 / 管理工作区 API Key | ✅ | — |
Agent ID
除了凭据,对话还需要知道和哪个 Agent 对话,也就是 Agent ID:一个形如 56941e40-47ad-49b0-bf88-cb8845b06c0e 的 UUID。建议和 API Key 一样放进环境变量,本文档统一叫它 OPENHEX_AGENT_ID。
在网页上找到它
- 打开 app.openhex.tech,在首页的 Agent 列表里点开要调用的 Agent。
- 看浏览器地址栏:
https://app.openhex.tech/console/<Agent ID>/…,/console/后面那一段就是 Agent ID。
用接口列出
用个人 API Key 列出你名下的全部 Agent,从返回里取 id:
curl https://api.openhex.tech/api/v2/agents \
-H "Authorization: Bearer mysta_..."
# → [ { "id": "56941e40-…", "name": "大顺", "is_public": true, … }, … ]
服务商后端持有工作区 API Key 时,用 client.workspace(slug).listAgents() 列出工作区里的 Agent,见读取 Agent。
在代码里使用
SDK 不会自动读取 OPENHEX_AGENT_ID(只有 OPENHEX_API_KEY 有环境变量兜底),需要显式传入:
export OPENHEX_API_KEY=mysta_...
export OPENHEX_AGENT_ID=56941e40-...
const client = new OpenhexClient({ agentId: process.env.OPENHEX_AGENT_ID });
Agent ID 不是密钥,可以出现在前端代码里;但浏览器里读不到服务器的环境变量。Next.js 需要加
NEXT_PUBLIC_前缀(例如NEXT_PUBLIC_OPENHEX_AGENT_ID)才会打包进前端。API Key 不要这样做。
在代码里传入
import { OpenhexClient } from '@openhex-ai/agent-sdk';
const client = new OpenhexClient({ apiKey: 'mysta_...' });
在 Node.js 里可以省略 apiKey,SDK 会读取环境变量 OPENHEX_API_KEY:
export OPENHEX_API_KEY=mysta_...
const client = new OpenhexClient(); // 从 OPENHEX_API_KEY 读取
两处都没有时,构造函数立即抛出 AuthenticationError,不会发出任何请求。浏览器里没有环境变量,必须显式传入。
浏览器里的正确做法
⚠️ 个人 API Key 和工作区 API Key 都绝不能进入浏览器、小程序包或 App 安装包。它们等同于账号 / 工作区的全部权限,打包进前端就等于公开。
客户端只拿会话令牌。标准做法是你的后端提供一个接口,按你自己的登录态为用户换发令牌:
// 后端
const ws = new OpenhexClient({ apiKey: process.env.OPENHEX_WORKSPACE_KEY! })
.workspace(process.env.OPENHEX_WORKSPACE_SLUG!);
app.post('/openhex/token', async (req, res) => {
const { token, expires_at } = await ws.startVisitorSession({
sp_user_ref: req.user.id,
ttl_seconds: 1800,
});
res.json({ token, expires_at });
});
// 前端
<ChatWidget agentId="…" getToken={() => fetch('/openhex/token', { method: 'POST' }).then(r => r.json()).then(d => d.token)} />
如果你更希望浏览器完全不接触任何 OpenHex 凭据,也可以在你的后端做一层反向代理,由代理替换 Authorization 头。这时浏览器端传一个明显是占位符的值即可:
new OpenhexClient({ baseUrl: '/openhex-proxy', apiKey: 'injected-by-proxy' });
占位符不要用 mysta_ / sk_ 开头——万一代理忘了替换,上游返回的 401 一眼就能看出原因。
连接配置
| 配置 | 默认值 | 说明 |
|---|---|---|
apiKey | OPENHEX_API_KEY | 上述三种凭据之一 |
baseUrl | https://api.openhex.tech | 平台 API 地址,走代理时改成代理地址 |
timeoutMs | 30000 | 非流式请求的超时(毫秒) |
fetch | 全局 fetch | 自定义 fetch 实现(测试、特殊运行时) |
SDK 只会把凭据发往
baseUrl所在的域名。把一个其他域名的完整 URL 传给底层请求方法,SDK 会直接拒绝并抛出OpenhexSdkError,避免凭据被带到别处。
凭据相关的错误
| 状态码 | 常见原因 |
|---|---|
401 | 凭据缺失、无效或已过期;或者用错了类型(例如用个人 Key 调只接受工作区 Key 的方法) |
403 | 凭据有效但无权访问(例如工作区 Key 和 slug 不属于同一个工作区、Key 已吊销、成员已停用) |
404 | 对当前凭据而言资源不存在(例如会话令牌访问别人 Agent 的训练接口) |
完整的错误处理见错误处理。
下一步
- 快速开始 — 用个人 API Key 跑通第一次对话
- 工作区 API 概览 — 签发工作区 API Key
- 会话令牌 — 给你的用户签发令牌