Skip to content

Commit aa8ba7b

Browse files
authored
docs(js-sdk): add SDK doc pages + type-drift guard (#106 follow-ups) (#127)
* docs(js-sdk): add SDK doc pages + type-drift guard (#106 follow-ups) Closes two of the #106 follow-ups: - Type-drift guard: a vitest test asserts packages/js-sdk/src/types.ts stays byte-identical to packages/mcp/src/types.ts (the JS SDK types are a maintained copy of the MCP types, which track the OpenAPI contract). It fails if the two ever drift, prompting a re-copy. Gated by the existing js-sdk-tests CI job. - Docs: js-sdk.md in all three doc variants (en-US, zh-CN, cn/zh-CN, the last with qveris.cn region adaptations), mirroring python-sdk.md; a TypeScript SDK section added to getting-started in each variant; the new paths registered in the docs-to-website sync workflow. The third follow-up (Vercel AI SDK adapter) belongs to the framework adapters issue (#109), not #106. * docs: fix js-sdk link depth in cn/zh-CN and restore en-US line endings Review fixes for #127: - docs/cn/zh-CN/getting-started.md sits one level deeper, so the packages/js-sdk link needs ../../../ (matching the sibling python-sdk link), not ../../ which resolved to a nonexistent docs/packages/js-sdk. - Re-applied the en-US TypeScript SDK section preserving the file's original line endings, dropping the spurious CRLF churn. * test(js-sdk): normalize line endings in the types-drift guard Addresses a review note: comparing the two types.ts files byte-for-byte could spuriously fail on a Windows checkout where core.autocrlf converts one file to CRLF. Normalize CRLF->LF before comparing so the guard tracks type content, not the checkout's line-ending style.
1 parent f404ad6 commit aa8ba7b

8 files changed

Lines changed: 607 additions & 0 deletions

File tree

.github/workflows/sync-docs-to-website.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ on:
3636
- "docs/en-US/python-sdk.md"
3737
- "docs/zh-CN/python-sdk.md"
3838
- "docs/cn/zh-CN/python-sdk.md"
39+
- "docs/en-US/js-sdk.md"
40+
- "docs/zh-CN/js-sdk.md"
41+
- "docs/cn/zh-CN/js-sdk.md"
3942
- ".github/workflows/sync-docs-to-website.yml"
4043
workflow_dispatch:
4144

docs/cn/zh-CN/getting-started.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,32 @@ if __name__ == "__main__":
141141

142142
---
143143

144+
### 使用 QVeris TypeScript SDK
145+
146+
TypeScript/JavaScript SDK 位于本单体仓库的 [`packages/js-sdk`](../../../packages/js-sdk)。安装已发布的包:
147+
148+
```bash
149+
npm install @qverisai/sdk
150+
```
151+
152+
这是一个零依赖的类型化客户端(原生 `fetch`,Node.js 18+)。完整指南(配置、API 参考、类型化响应、错误处理)见 [TypeScript SDK](js-sdk.md)
153+
154+
```typescript
155+
import { Qveris } from '@qverisai/sdk';
156+
157+
const qveris = Qveris.fromEnv(); // 读取 QVERIS_API_KEY、QVERIS_BASE_URL
158+
159+
const discovered = await qveris.discover('weather forecast API', { limit: 5 });
160+
const tool = discovered.results[0];
161+
const result = await qveris.call(tool.tool_id, {
162+
parameters: { city: 'London' },
163+
searchId: discovered.search_id,
164+
});
165+
console.log(result.execution_id, result.success, result.billing);
166+
```
167+
168+
---
169+
144170
### 直接调用 QVeris REST API
145171

146172
**Base URL**

docs/cn/zh-CN/js-sdk.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# QVeris TypeScript SDK
2+
3+
类型化的 TypeScript/JavaScript SDK,让你在自己的 Agent 和应用中发现、检查、调用并审计 10,000+ 真实已验证的 API 能力。
4+
5+
`@qverisai/sdk` 是对 QVeris REST API(`discover``inspect``call``credits``usage``ledger`)的轻量类型化封装。它**零运行时依赖**——使用平台原生 `fetch`(Node.js 18+)——并与 [Python SDK](python-sdk.md)[MCP 服务器](mcp-server.md) 保持一致的通信语义。
6+
7+
## 安装
8+
9+
```bash
10+
npm install @qverisai/sdk
11+
```
12+
13+
需要 Node.js 18+(原生 `fetch`)。该包仅支持 ESM。
14+
15+
## 认证
16+
17+
SDK 从环境变量 `QVERIS_API_KEY` 读取 API 密钥,并通过 `QVERIS_BASE_URL` 指向 API 地址。请设置:
18+
19+
```bash
20+
export QVERIS_API_KEY="your-api-key"
21+
export QVERIS_BASE_URL="https://qveris.cn/api/v1"
22+
```
23+
24+
[qveris.cn](https://qveris.cn) 获取密钥。可从环境变量创建客户端,也可以显式传入配置:
25+
26+
```typescript
27+
import { Qveris } from '@qverisai/sdk';
28+
29+
const qveris = Qveris.fromEnv();
30+
//
31+
const explicit = new Qveris({
32+
apiKey: 'your-api-key',
33+
baseUrl: 'https://qveris.cn/api/v1',
34+
});
35+
```
36+
37+
区域解析优先级为:显式 `baseUrl` > `QVERIS_BASE_URL` > `QVERIS_REGION``global` | `cn`)> 密钥前缀自动识别(`sk-cn-…` → 中国)。
38+
39+
## 快速开始
40+
41+
核心工作流是 **discover → inspect → call**,然后可选地**审计**发生了什么。所有方法都返回 Promise。
42+
43+
```typescript
44+
import { Qveris } from '@qverisai/sdk';
45+
46+
const qveris = Qveris.fromEnv();
47+
48+
// 1. 用自然语言发现能力(免费)
49+
const discovered = await qveris.discover('weather forecast API', { limit: 5 });
50+
const tool = discovered.results[0];
51+
52+
// 2. 检查所选能力的完整参数
53+
const inspected = await qveris.inspect(tool.tool_id, { searchId: discovered.search_id });
54+
const selected = inspected.results[0];
55+
56+
// 3. 调用(可能消耗积分)
57+
const params = selected.examples?.sample_parameters ?? { city: 'London' };
58+
const result = await qveris.call(selected.tool_id, {
59+
parameters: params,
60+
searchId: discovered.search_id,
61+
maxResponseSize: 20480,
62+
});
63+
console.log(result.success, result.result);
64+
65+
// 4. 审计最终扣费结果
66+
const usage = await qveris.usage({ execution_id: result.execution_id, summary: true });
67+
const ledger = await qveris.ledger({ summary: true, limit: 5 });
68+
console.log(usage.total, ledger.total);
69+
```
70+
71+
客户端基于 `fetch`、无状态,无需手动关闭连接。
72+
73+
## 配置参考
74+
75+
`new Qveris(config)` 接受:
76+
77+
| 字段 | 环境变量 | 默认值 | 说明 |
78+
|------|---------|--------|------|
79+
| `apiKey` | `QVERIS_API_KEY` | —(必填) | API 密钥,以 `Authorization: Bearer ...` 发送 |
80+
| `baseUrl` | `QVERIS_BASE_URL` | 按区域解析 | API 基础地址(优先级最高) |
81+
| `timeoutMs` || `30000` | 默认请求超时(`call` 默认 `120000`|
82+
83+
未显式给出 `baseUrl` 时,`QVERIS_REGION``global` | `cn`)强制指定区域。`Qveris.fromEnv(overrides?)``QVERIS_API_KEY` 构建客户端,并接受相同的非密钥选项。
84+
85+
## API 参考
86+
87+
### `Qveris`
88+
89+
| 方法 | REST 端点 | 用途 |
90+
|------|-----------|------|
91+
| `discover(query, options?)` | `POST /search` | 用自然语言发现能力(免费) |
92+
| `inspect(toolIds, options?)` | `POST /tools/by-ids` | 获取能力完整元数据(免费) |
93+
| `call(toolId, options)` | `POST /tools/execute` | 执行能力(可能消耗积分) |
94+
| `credits()` | `GET /auth/credits` | 当前积分余额与分桶 |
95+
| `usage(filters?)` | `GET /auth/usage/history/v2` | 审计请求状态与扣费结果 |
96+
| `ledger(filters?)` | `GET /auth/credits/ledger` | 查看最终积分余额变动 |
97+
98+
选项结构:
99+
100+
- `discover(query, { limit?, sessionId?, timeoutMs? })`
101+
- `inspect(toolIds, { searchId?, sessionId?, timeoutMs? })` —— `toolIds` 接受单个字符串或数组;**空数组会短路**,直接返回空响应而不发起网络请求。
102+
- `call(toolId, { parameters, searchId?, sessionId?, maxResponseSize?, timeoutMs? })`
103+
104+
`usage(...)``ledger(...)` 接受过滤对象,如 `start_date``end_date``summary``bucket``charge_outcome``execution_id``search_id``direction``entry_type``min_credits``max_credits``limit``page``page_size`
105+
106+
## 类型化响应
107+
108+
所有方法返回与公开 OpenAPI 合同对齐的类型化结果。未知的后端字段会透传,因此新增的 API 元数据不会破坏旧版 SDK 客户端。
109+
110+
- 发现 / 检查:`SearchResponse``results: ToolInfo[]``ToolInfo``tool_id``name``description``categories`(对象或字符串)、`capabilities``params``examples``stats``billing_rule``expected_cost`,以及(仅 discover)`why_recommended`
111+
- 调用:`ExecuteResponse`,含 `execution_id``success``result``error_message``billing``CompactBillingStatement`)、`cost``remaining_credits`
112+
- 用量审计:`UsageEventsResponse``items: UsageEventItem[]``total``summary`
113+
- 积分账本:`CreditsLedgerResponse``items: CreditsLedgerItem[]``total``summary`
114+
115+
```typescript
116+
import type { ExecuteResponse } from '@qverisai/sdk';
117+
118+
function explain(result: ExecuteResponse): string {
119+
if (!result.success) return `failed: ${result.error_message}`;
120+
const charged = result.billing?.summary ?? 'no billing info';
121+
return `ok (${charged}); remaining=${result.remaining_credits}`;
122+
}
123+
```
124+
125+
## 接入你自己的 Agent 循环
126+
127+
类型化客户端天然可作为任何 LLM Agent 框架的工具后端:把 `discover` / `inspect` / `call` 作为工具暴露给模型,再把工具调用路由回客户端。由于 `discover` 返回 `why_recommended``expected_cost`,你的 Agent 可以在调用前对能力进行排序和预算控制。
128+
129+
## 错误处理
130+
131+
每个失败请求都会抛出 `QverisApiError`——一个 `Error` 子类,携带:
132+
133+
| 属性 | 说明 |
134+
|------|------|
135+
| `status` | HTTP 状态码(`0` 网络错误,`408` 超时,`402` 积分不足,……) |
136+
| `details` | 服务端返回的错误体(如有) |
137+
| `observability` | 请求上下文(operation、endpoint、request id),用于诊断 |
138+
| `cause` | 更底层的传输/运行时原因(如有) |
139+
140+
```typescript
141+
import { Qveris, QverisApiError } from '@qverisai/sdk';
142+
143+
const qveris = Qveris.fromEnv();
144+
try {
145+
await qveris.call('some.tool.v1', { parameters: {} });
146+
} catch (err) {
147+
if (err instanceof QverisApiError && err.status === 402) {
148+
// 积分不足 —— err.message 含购买链接
149+
}
150+
}
151+
```
152+
153+
`result.success` 只反映能力调用本身。**不要**把它当作最终扣费结果——请用 `usage(...)` / `ledger(...)` 确认扣费。
154+
155+
## 兼容性
156+
157+
- Node.js `>=18`(原生 `fetch`)。仅 ESM。
158+
- 响应类型与公开方法尽量遵循增量兼容。
159+
- 破坏性变更需要主版本号提升并附迁移说明。
160+
161+
> `@qverisai/sdk``0.1.x` 版本是早期以 MCP 为中心的 SDK,现已被 [`@qverisai/mcp`](mcp-server.md) 取代。本文档所述的类型化 REST 客户端从 **`0.2.0`** 起。
162+
163+
## 链接
164+
165+
- 包:[npm 上的 `@qverisai/sdk`](https://www.npmjs.com/package/@qverisai/sdk)
166+
- 源码:[`packages/js-sdk`](https://github.com/QVerisAI/qveris-agent-toolkit/tree/main/packages/js-sdk)
167+
- REST API:[rest-api.md](rest-api.md)
168+
- 获取 API 密钥:[qveris.cn](https://qveris.cn)

docs/en-US/getting-started.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,30 @@ if __name__ == "__main__":
141141

142142
---
143143

144+
### Use the QVeris TypeScript SDK
145+
146+
The TypeScript/JavaScript SDK lives in this monorepo at [`packages/js-sdk`](../../packages/js-sdk). Install the published package with:
147+
148+
```bash
149+
npm install @qverisai/sdk
150+
```
151+
152+
It is a zero-dependency typed client (native `fetch`, Node.js 18+). For the full guide (config, API reference, typed responses, error handling), see [TypeScript SDK](js-sdk.md).
153+
154+
```typescript
155+
import { Qveris } from '@qverisai/sdk';
156+
157+
const qveris = Qveris.fromEnv(); // reads QVERIS_API_KEY
158+
159+
const discovered = await qveris.discover('weather forecast API', { limit: 5 });
160+
const tool = discovered.results[0];
161+
const result = await qveris.call(tool.tool_id, {
162+
parameters: { city: 'London' },
163+
searchId: discovered.search_id,
164+
});
165+
console.log(result.execution_id, result.success, result.billing);
166+
```
167+
144168
### Directly call the QVeris REST API
145169

146170
**Base URL**

0 commit comments

Comments
 (0)