@acosmi/sdk-ts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/browser/index.js +3950 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/index.js +3950 -0
- package/dist/index.js.map +1 -0
- package/dist/node/adapters/anthropic.cjs +257 -0
- package/dist/node/adapters/anthropic.cjs.map +1 -0
- package/dist/node/adapters/anthropic.d.cts +39 -0
- package/dist/node/adapters/anthropic.d.ts +39 -0
- package/dist/node/adapters/anthropic.js +254 -0
- package/dist/node/adapters/anthropic.js.map +1 -0
- package/dist/node/adapters/openai.cjs +472 -0
- package/dist/node/adapters/openai.cjs.map +1 -0
- package/dist/node/adapters/openai.d.cts +64 -0
- package/dist/node/adapters/openai.d.ts +64 -0
- package/dist/node/adapters/openai.js +465 -0
- package/dist/node/adapters/openai.js.map +1 -0
- package/dist/node/index-C3Z_84Bv.d.cts +992 -0
- package/dist/node/index-C3Z_84Bv.d.ts +992 -0
- package/dist/node/index-nvLKgCm9.d.cts +147 -0
- package/dist/node/index-nvLKgCm9.d.ts +147 -0
- package/dist/node/index.cjs +4024 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +791 -0
- package/dist/node/index.d.ts +791 -0
- package/dist/node/index.js +3950 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/sanitize/index.cjs +248 -0
- package/dist/node/sanitize/index.cjs.map +1 -0
- package/dist/node/sanitize/index.d.cts +1 -0
- package/dist/node/sanitize/index.d.ts +1 -0
- package/dist/node/sanitize/index.js +217 -0
- package/dist/node/sanitize/index.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Acosmi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# @acosmi/sdk-ts
|
|
2
|
+
|
|
3
|
+
> Acosmi 模型网关 TypeScript SDK — 双格式(Anthropic + OpenAI)多端(浏览器 / Node ≥18 / Deno / Bun)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@acosmi/sdk-ts)
|
|
6
|
+
|
|
7
|
+
## 状态
|
|
8
|
+
|
|
9
|
+
- 端口源:[acosmi-sdk-go](https://github.com/acosmi/acosmi-sdk-go) v1.0.0(与 Go SDK 联动稳定测试版)
|
|
10
|
+
- 当前版本:1.0.0(稳定测试版,与 Go SDK 联动 1.0.x)
|
|
11
|
+
- 测试:36/36 vitest 全绿,typecheck/lint/build 0 错误
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install @acosmi/sdk-ts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 快速开始
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Client, allScopes } from '@acosmi/sdk-ts';
|
|
23
|
+
|
|
24
|
+
const client = new Client({ serverURL: 'https://acosmi.com' });
|
|
25
|
+
await client.login('My App', allScopes());
|
|
26
|
+
|
|
27
|
+
const resp = await client.chat('claude-opus-4-7', {
|
|
28
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
29
|
+
maxTokens: 1024,
|
|
30
|
+
});
|
|
31
|
+
console.log(resp.content);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 双格式红线(设计核心)
|
|
35
|
+
|
|
36
|
+
SDK 同时提供 **Anthropic + OpenAI 两条 endpoint**,**等地位**,对应两个不同下游产品。
|
|
37
|
+
|
|
38
|
+
| Adapter | 端点 | 用途 |
|
|
39
|
+
| ------------------ | ------------------------------------- | ----------------------------------- |
|
|
40
|
+
| `AnthropicAdapter` | `POST /managed-models/:id/anthropic` | Anthropic 原生格式(含 thinking 等)|
|
|
41
|
+
| `OpenAIAdapter` | `POST /managed-models/:id/chat` | OpenAI 兼容格式(DeepSeek/GLM 等) |
|
|
42
|
+
|
|
43
|
+
路由由 `getAdapterForModel(model)` 按 ManagedModel 的 `preferredFormat` / `supportedFormats` 决策:
|
|
44
|
+
|
|
45
|
+
1. `preferredFormat` 非空 → 按值(`anthropic` | `openai`)
|
|
46
|
+
2. `supportedFormats` 含 `anthropic` → AnthropicAdapter
|
|
47
|
+
3. `supportedFormats` 含 `openai` → OpenAIAdapter
|
|
48
|
+
4. 两字段均空(旧上游)→ 按 provider 名回落
|
|
49
|
+
|
|
50
|
+
`client.chat()` / `client.chatStream()` 内部自动调 `getAdapterForModel`,使用方无需关心。
|
|
51
|
+
|
|
52
|
+
## 多端
|
|
53
|
+
|
|
54
|
+
| 平台 | HTTP | SSE | WebSocket | TokenStore |
|
|
55
|
+
| --------------- | ------ | ---------------- | ---------------------------------------- | -------------------------------- |
|
|
56
|
+
| 浏览器 | fetch | ReadableStream | WebSocket | `LocalStorageTokenStore` |
|
|
57
|
+
| Node ≥18 | fetch | ReadableStream | WebSocket(Node 22+)/ `ws`(18-21 自装)| `FileTokenStore` (~/.acosmi/) |
|
|
58
|
+
| Deno / Bun | fetch | ReadableStream | WebSocket | File |
|
|
59
|
+
|
|
60
|
+
构建产物:`dist/{node,browser}/` 各自 ESM + CJS + `.d.ts`,主入口约 120 KB。
|
|
61
|
+
|
|
62
|
+
## 流式
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const stream = client.chatStream('claude-opus-4-7', {
|
|
66
|
+
messages: [{ role: 'user', content: '写一首诗' }],
|
|
67
|
+
maxTokens: 1024,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
for await (const ev of stream) {
|
|
71
|
+
if (ev.event === 'content_block_delta' && ev.data) {
|
|
72
|
+
// 解析 delta 输出 token
|
|
73
|
+
process.stdout.write(parseDelta(ev.data));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`chatStreamWithUsage()` 返回带 usage/error/sources 标签的 AsyncIterable,便于聚合统计(详见 `src/client.ts`)。
|
|
79
|
+
|
|
80
|
+
## 认证
|
|
81
|
+
|
|
82
|
+
### 浏览器内 / 自动 OAuth(推荐)
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
await client.login('My App', allScopes()); // 自动跳转浏览器完成 OAuth
|
|
86
|
+
const token = await client.ensureToken(); // 拿到当前有效 access token
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 手动 OAuth(CLI / 自定义流程)
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { discover, register, authorize, exchangeCode } from '@acosmi/sdk-ts';
|
|
93
|
+
|
|
94
|
+
const meta = await discover('https://acosmi.com');
|
|
95
|
+
const reg = await register(meta, 'My CLI', allScopes());
|
|
96
|
+
const result = await authorize(meta, reg, allScopes(), {
|
|
97
|
+
onEvent: (ev) => console.log(ev.type, ev.url),
|
|
98
|
+
});
|
|
99
|
+
const tokens = await exchangeCode(meta, reg, result.code, result.codeVerifier);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Token 持久化
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { Client, FileTokenStore, LocalStorageTokenStore } from '@acosmi/sdk-ts';
|
|
106
|
+
|
|
107
|
+
// Node — 默认 ~/.acosmi/tokens.json,可自定义路径
|
|
108
|
+
const client = new Client({ serverURL: 'https://acosmi.com', tokenStore: new FileTokenStore('./my-tokens.json') });
|
|
109
|
+
|
|
110
|
+
// 浏览器 — 自动用 LocalStorage(无 LocalStorage 时退化为内存)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## API 总览
|
|
114
|
+
|
|
115
|
+
| 模块 | 主要方法 |
|
|
116
|
+
| ------------ | ------------------------------------------------------------------------------------ |
|
|
117
|
+
| **Chat** | `chat`, `chatStream`, `chatStreamWithUsage` |
|
|
118
|
+
| **Auth** | `login`, `logout`, `ensureToken`, `forceRefresh`, `discover`, `authorize`, `exchangeCode`, `refreshToken` |
|
|
119
|
+
| **Models** | `listModels`, `listModelsWithStatus`, `getModelCapabilities`, `getQuotaSummary` |
|
|
120
|
+
| **Skills** | `browseSkills`, `browseSkillsList`, `getSkillDetail`, `resolveSkill`, `installSkill`, `downloadSkill`, `uploadSkill`, `generateSkill`, `optimizeSkill`, `validateSkill` |
|
|
121
|
+
| **Tools** | `listTools`, `getTool` |
|
|
122
|
+
| **Wallet** | `getWalletStats`, `getWalletTransactions` |
|
|
123
|
+
| **Entitlements** | `getBalance`, `getBalanceDetail`, `listEntitlements`, `claimMonthlyFree`, `getByModel`, `listBuckets`, `listCoefficients` |
|
|
124
|
+
| **Packages** | `listTokenPackages`, `buyTokenPackage`, `getOrderStatus`, `waitForPayment` |
|
|
125
|
+
| **Notifications** | `listNotifications`, `getUnreadCount`, `markNotificationRead`, `registerDevice`, `listNotificationPreferences` |
|
|
126
|
+
| **Bug Report** | `submitBugReport`, `getBugReport` |
|
|
127
|
+
| **Web Search** | `newWebSearchTool` (factory) |
|
|
128
|
+
|
|
129
|
+
完整签名见 `dist/node/index.d.ts`,IDE 自带补全。
|
|
130
|
+
|
|
131
|
+
### 示例:Skill 商店搜索
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { Client } from '@acosmi/sdk-ts';
|
|
135
|
+
|
|
136
|
+
const client = new Client({ serverURL: 'https://acosmi.com' });
|
|
137
|
+
|
|
138
|
+
// 公共端点 — 无需登录
|
|
139
|
+
const result = await client.browseSkills(
|
|
140
|
+
1, 20, // page, pageSize
|
|
141
|
+
'ACTION', // category: ACTION|TRIGGER|TRANSFORM|''
|
|
142
|
+
'关键词', // keyword
|
|
143
|
+
'', // tag
|
|
144
|
+
'BUILTIN', // source: BUILTIN|COMMUNITY|USER|''
|
|
145
|
+
);
|
|
146
|
+
console.log(result.total, result.items);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 示例:LLM 联网搜索(Anthropic Web Search Tool)
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { Client, newWebSearchTool } from '@acosmi/sdk-ts';
|
|
153
|
+
|
|
154
|
+
const tool = newWebSearchTool({
|
|
155
|
+
max_uses: 5,
|
|
156
|
+
allowed_domains: ['anthropic.com', 'developer.mozilla.org'],
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const resp = await client.chat('claude-opus-4-7', {
|
|
160
|
+
messages: [{ role: 'user', content: '查一下 Web Components 最新规范' }],
|
|
161
|
+
maxTokens: 2048,
|
|
162
|
+
tools: [tool],
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`AllowedDomains` / `BlockedDomains` 互斥,同时传入抛 `Error`。
|
|
167
|
+
|
|
168
|
+
### 示例:钱包 + 余额 + 流量包购买
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// 金额字段是 string(Go json.Number 端口,避免浮点精度丢失)
|
|
172
|
+
const stats = await client.getWalletStats();
|
|
173
|
+
// { balance: "100.00", monthlyConsumption: "32.50", monthlyRecharge: "150.00" }
|
|
174
|
+
|
|
175
|
+
const balance = await client.getBalance(); // 聚合权益余额
|
|
176
|
+
|
|
177
|
+
const pkgs = await client.listTokenPackages();
|
|
178
|
+
const order = await client.buyTokenPackage(pkgs[0].id, { payMethod: 'wechat' });
|
|
179
|
+
const status = await client.waitForPayment(order.id, 2000); // 2s 轮询直到终态
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 示例:Bug Report(CrabCode CLI 反馈端点)
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
// reportData 任意 JSON 可编码对象,后端做脱敏 + 字段抽取(无须客户端过滤密钥)
|
|
186
|
+
const result = await client.submitBugReport({
|
|
187
|
+
description: 'Stream 卡住',
|
|
188
|
+
platform: 'darwin',
|
|
189
|
+
version: '1.0.0',
|
|
190
|
+
errors: [/* ... */],
|
|
191
|
+
transcript: [/* ... */],
|
|
192
|
+
});
|
|
193
|
+
console.log(result.feedback_id, result.detail_url);
|
|
194
|
+
|
|
195
|
+
// 公开页 ViewModel(无需 auth)
|
|
196
|
+
const view = await client.getBugReport(result.feedback_id);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 错误处理
|
|
200
|
+
|
|
201
|
+
所有方法 `throw` 类型化错误(不是 Go 风格多返回值):
|
|
202
|
+
|
|
203
|
+
| 错误类型 | 触发 |
|
|
204
|
+
| -------------------- | -------------------------------------------- |
|
|
205
|
+
| `HTTPError` | 4xx/5xx,含 `status` / `body` / `requestID` |
|
|
206
|
+
| `NetworkError` | TCP/DNS/TLS 失败 |
|
|
207
|
+
| `StreamError` | SSE 流解析失败 |
|
|
208
|
+
| `BusinessError` | 网关返回 `code !== 0`,含 `code` / `bizMsg` |
|
|
209
|
+
| `RateLimitError` | 429(含 `retryAfter`) |
|
|
210
|
+
| `OrderTerminalError` | `waitForPayment` 终态失败 |
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { HTTPError, BusinessError } from '@acosmi/sdk-ts';
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
await client.chat(...);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
if (e instanceof HTTPError && e.status === 401) await client.login(...);
|
|
219
|
+
if (e instanceof BusinessError) console.error(e.code, e.bizMsg);
|
|
220
|
+
throw e;
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## AbortSignal
|
|
225
|
+
|
|
226
|
+
每个异步方法都接 `signal?: AbortSignal`,用于取消请求或流:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
const ctl = new AbortController();
|
|
230
|
+
setTimeout(() => ctl.abort(), 5000);
|
|
231
|
+
|
|
232
|
+
await client.chat('claude-opus-4-7', { ... }, ctl.signal);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 开发
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
npm install
|
|
239
|
+
npm run typecheck
|
|
240
|
+
npm run lint
|
|
241
|
+
npm test
|
|
242
|
+
npm run build
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
[MIT](./LICENSE) — Copyright (c) 2026 Acosmi
|