@acosmi/sdk-ts 1.0.2 → 1.2.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/CHANGELOG.md CHANGED
@@ -5,6 +5,62 @@ All notable changes to `@acosmi/sdk-ts` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] — 2026-05-18
9
+
10
+ ### Added
11
+
12
+ - **`ManagedModel.inputModalities`** — 新增可选字段, 类型 `Array<'text' | 'image'>`, 描述模型可接收的用户输入模态; 'image' 表示模型可直接接收 screenshot/image 输入. listModels / listModelsWithStatus 在写缓存与返回前会归一化上游 snake_case 字段名 `input_modalities` → camelCase `inputModalities` (兼容老网关), camelCase 与 snake_case 同时存在时 camelCase 胜.
13
+
14
+ - **`ModelCapabilities.supports_desktop_visual_understanding`** — 新增可选字段, 标识模型适合作为桌面截图解析 sidecar (输入 screenshot, 输出结构化 UI 描述, 供非多模态主模型消费). 与 `inputModalities=['image']` 是正交两件事: 前者描述"模型能不能吃图", 后者描述"运营是否把该模型标为桌面 UI 解析专用 sidecar". `zeroModelCapabilities()` 显式置 `false`, 避免 `undefined` 导致调用方误判.
15
+
16
+ - **`InputModality`** 类型导出 — `'text' | 'image'`.
17
+
18
+ - **Model catalog helpers (4 个)** — CrabCode desktop automation / computer-use 选模型用, 严格按 SDK 字段, 禁止模型名 substring 推断:
19
+ - `modelSupportsInputModality(model, modality): boolean`
20
+ - `modelSupportsImageInput(model): boolean`
21
+ - `findFirstModelByInputModality(models, modality): ManagedModel | null` — 按 catalog 顺序, 跳过 `isEnabled === false`
22
+ - `findDesktopVisualUnderstandingModel(models): ManagedModel | null` — 选择规则: isEnabled !== false + capabilities.supports_desktop_visual_understanding === true + inputModalities 含 'image' + isDefault 优先 / 否则 catalog 顺序第一个
23
+
24
+ ### Notes
25
+
26
+ - 上游 `ManagedModel` 缺失 `inputModalities` 时, SDK 保留 `undefined` 不自动补 `['text']` — 调用方必须保守按 text-only / unknown 处理, 严禁默认假设支持 image.
27
+ - 客户端不应硬编码模型名, 应完全依赖 SDK catalog 能力字段做模型选择.
28
+ - 23 新单测全绿 (8 listModels 归一化 + 15 helpers); 全量 79/79 passed, typecheck/lint/build clean.
29
+
30
+ ---
31
+
32
+ ## [1.1.0] — 2026-05-06
33
+
34
+ ### Added
35
+
36
+ - **Agent Runs SDK Gateway** — 新增 `client.agentRuns` namespace,作为 CrabDesign、CrabCode、CrabClaw 等下游产品接入 Acosmi 云端智能体循环的正式 SDK 协议边界:
37
+ - `create(req, signal?)`
38
+ - `stream(runId, opts?, signal?)`
39
+ - `run(req, opts?, signal?)`
40
+ - `cancel(runId, signal?)`
41
+ - `get(runId, signal?)`
42
+ - `listArtifacts(runId, signal?)`
43
+ - `downloadArtifact(runId, artifactId, signal?)`
44
+ - `submitLocalToolResult(runId, result, signal?)`
45
+ - `runWithLocalTools(req, handlers, opts?, signal?)`
46
+
47
+ - **Agent Run protocol types** — 新增 `AgentRunCreateRequest`、`AgentRunStreamEvent` discriminated union、`AgentRunArtifact`、`AgentRunStreamError` 等公开类型。SDK public API 使用 camelCase,HTTP wire-format 使用 snake_case。
48
+
49
+ - **Local tool bridge protocol** — SDK 不内置产品专属本地文件读取逻辑;`local_tool_request` 由下游处理,并通过 `submitLocalToolResult({ requestId, ok, content | error })` 返回。便捷封装 `runWithLocalTools` 支持 handler 超时、拒绝和取消。
50
+
51
+ - **Durable Agent Run Gateway contract** — Nexus Agent Run Gateway 使用租户隔离的 durable run store 持久化 run 状态、SSE event、artifact 和 local tool result;stream 支持断线后的 durable event replay,并将 local tool request 真正桥接到 ADK function call 等待点。
52
+
53
+ - **Exact usage settlement** — Agent Runs 结算只接受 provider/ADK 透传的 `exact: true` usage,并通过 tk-dist `SettlePrecise(input/output/cacheRead/cacheCreate)` 精算;若 provider 未返回精确 usage,服务端会释放 hold 并返回 `usage_missing_released`,不会用字符数或 token 估算扣费。
54
+
55
+ ### Changed
56
+
57
+ - **401 retry policy for Agent Runs** — Agent Runs 客户端只对 GET/stream/download 等安全查询做单次 401 refresh retry;`create`、`submitLocalToolResult` 等可能产生副作用的 POST 不自动重放,避免重复创建 run 或重复计费。
58
+
59
+ ### Tests
60
+
61
+ - 新增 `test/agent-runs.test.ts`,覆盖 create 字段序列化、完整流事件解析、401 refresh 策略、error 事件结构化抛出、local tool result payload、artifact 下载文件名/content-type 解析。
62
+ - `scripts/smoke-pack.mjs` 增加 consumer 视角的 `client.agentRuns` 类型调用验证。
63
+
8
64
  ## [1.0.2] — 2026-05-06
9
65
 
10
66
  ### Fixed
@@ -96,5 +152,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
96
152
  - 36/36 vitest 全绿,源码 typecheck/lint/build 0 错误
97
153
  - 翻车机制:`prepublishOnly` 仅跑源码 typecheck/vitest/build,不验证 packed product 在 consumer 视角能否解析
98
154
 
155
+ [1.1.0]: https://github.com/acosmi/sdk-ts/releases/tag/v1.1.0
156
+ [1.0.2]: https://github.com/acosmi/sdk-ts/releases/tag/v1.0.2
99
157
  [1.0.1]: https://github.com/acosmi/sdk-ts/releases/tag/v1.0.1
100
158
  [1.0.0]: https://www.npmjs.com/package/@acosmi/sdk-ts/v/1.0.0
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # @acosmi/sdk-ts
2
2
 
3
- > Acosmi 模型网关 TypeScript SDK — 双格式(Anthropic + OpenAI)多端(浏览器 / Node ≥18 / Deno / Bun)
3
+ > Acosmi 模型网关 + Agent Run Gateway TypeScript SDK — 双格式(Anthropic + OpenAI)多端(浏览器 / Node ≥18 / Deno / Bun)
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/%40acosmi%2Fsdk-ts.svg)](https://www.npmjs.com/package/@acosmi/sdk-ts)
6
6
 
7
7
  ## 状态
8
8
 
9
9
  - 端口源:[acosmi-sdk-go](https://github.com/acosmi/acosmi-sdk-go) v1.0.0(与 Go SDK 联动稳定测试版)
10
- - 当前版本:**1.0.1**(稳定测试版,与 Go SDK 联动 1.0.x;1.0.0 deprecate due to broken packaging,详见 [CHANGELOG](./CHANGELOG.md))
11
- - 测试:36/36 vitest 全绿,typecheck/lint/build 0 错误;packed-tarball smoke (`npm run test:pack`) 在 prepublishOnly 闸内
12
- - 包链接:[npm](https://www.npmjs.com/package/@acosmi/sdk-ts/v/1.0.1) · [tarball](https://registry.npmjs.org/@acosmi/sdk-ts/-/sdk-ts-1.0.1.tgz) · [GitHub Release](https://github.com/acosmi/sdk-ts/releases/tag/v1.0.1) · [provenance](https://registry.npmjs.org/-/npm/v1/attestations/@acosmi%2fsdk-ts@1.0.1)(SLSA v1,CI 自动签)
10
+ - 当前版本:**1.2.0**(新增 `ManagedModel.inputModalities` + `ModelCapabilities.supports_desktop_visual_understanding` + 4 catalog helpers,供 CrabCode desktop automation / computer-use 选模型用;详见 [CHANGELOG](./CHANGELOG.md))
11
+ - 测试:79/79 vitest 全绿,typecheck/lint/build 0 错误;packed-tarball smoke (`npm run test:pack`) 在 prepublishOnly 闸内
12
+ - 包链接:[npm](https://www.npmjs.com/package/@acosmi/sdk-ts/v/1.2.0) · [tarball](https://registry.npmjs.org/@acosmi/sdk-ts/-/sdk-ts-1.2.0.tgz) · [GitHub Release](https://github.com/acosmi/sdk-ts/releases/tag/v1.2.0)
13
13
 
14
14
  ## 安装
15
15
 
@@ -78,6 +78,69 @@ for await (const ev of stream) {
78
78
 
79
79
  `chatStreamWithUsage()` 返回带 usage/error/sources 标签的 AsyncIterable,便于聚合统计(详见 `src/client.ts`)。
80
80
 
81
+ ## Agent Runs
82
+
83
+ `client.agentRuns` 是下游产品接入 Acosmi 云端智能体循环的正式 SDK 边界。CrabDesign、CrabCode、CrabClaw 等产品应通过这里创建、流式消费、取消、查询和下载智能体任务,不要直连 Nexus 内部 `/api/v4/chat/completions`。
84
+
85
+ 服务端 Agent Run Gateway 会按认证上下文做 `tenantId + userId` 隔离,run 状态、SSE event、artifact 和 local tool result 都是 durable store;任务执行会进入 Acosmi 统一 entitlement 预扣/结算/释放链路。结算只使用 provider/ADK 透传的精确 usage;如果 provider 未返回 `exact: true` usage,服务端会释放 hold,不会使用估算 token 扣费。
86
+
87
+ ```ts
88
+ import { Client, allScopes } from '@acosmi/sdk-ts';
89
+
90
+ const client = new Client({ serverURL: 'https://acosmi.com' });
91
+ await client.login('CrabDesign', allScopes());
92
+
93
+ const run = await client.agentRuns.create({
94
+ appId: 'crabdesign',
95
+ mode: 'design',
96
+ sessionId: 'session-optional',
97
+ input: 'Create a landing page mockup for a fintech dashboard',
98
+ activeSkillIds: ['brand-system'],
99
+ knowledgeBaseIds: ['kb-product'],
100
+ localContextPolicy: {
101
+ enabled: true,
102
+ readonly: true,
103
+ maxBytes: 128_000,
104
+ allowedTools: ['read_file'],
105
+ },
106
+ artifactPolicy: { enabled: true, maxFiles: 10 },
107
+ });
108
+
109
+ for await (const event of client.agentRuns.stream(run.runId, { throwOnError: false })) {
110
+ switch (event.type) {
111
+ case 'text_delta':
112
+ process.stdout.write(event.text);
113
+ break;
114
+ case 'reasoning_delta':
115
+ console.debug('[reasoning]', event.text);
116
+ break;
117
+ case 'local_tool_request': {
118
+ // SDK only defines the protocol. Product code owns local read-only tools.
119
+ const content = await readReadonlyLocalContext(event.name, event.input);
120
+ await client.agentRuns.submitLocalToolResult(run.runId, {
121
+ requestId: event.requestId,
122
+ ok: true,
123
+ content,
124
+ });
125
+ break;
126
+ }
127
+ case 'artifact': {
128
+ const file = await client.agentRuns.downloadArtifact(run.runId, event.artifact.id);
129
+ console.log('artifact', file.filename, file.contentType, file.data.byteLength);
130
+ break;
131
+ }
132
+ case 'error':
133
+ throw new Error(event.error.message);
134
+ }
135
+ }
136
+
137
+ await client.agentRuns.cancel(run.runId); // safe to call from UI cancel buttons
138
+ ```
139
+
140
+ 本地工具桥是显式 opt-in:SDK 不内置任何 CrabDesign/CrabCode 专属文件读取逻辑。`local_tool_request` 由下游处理,结果通过 `submitLocalToolResult({ requestId, ok, content | error })` 返回;拒绝、超时和取消都由下游 handler 控制。`allowedTools` 必须使用稳定的 ASCII function name,例如 `read_file`。
141
+
142
+ `stream(runId)` 支持 durable replay:断线后重新连接同一个 run,会先回放已持久化的 Agent Run SSE 事件,再继续消费运行中的事件。`usage` / `settle` 事件会暴露 `exact`、`cacheReadTokens`、`cacheCreateTokens` 等字段,便于下游展示真实结算状态。
143
+
81
144
  ## 认证
82
145
 
83
146
  ### 浏览器内 / 自动 OAuth(推荐)
@@ -116,8 +179,9 @@ const client = new Client({ serverURL: 'https://acosmi.com', tokenStore: new Fil
116
179
  | 模块 | 主要方法 |
117
180
  | ------------ | ------------------------------------------------------------------------------------ |
118
181
  | **Chat** | `chat`, `chatStream`, `chatStreamWithUsage` |
182
+ | **Agent Runs** | `agentRuns.create`, `agentRuns.stream`, `agentRuns.run`, `agentRuns.cancel`, `agentRuns.get`, `agentRuns.listArtifacts`, `agentRuns.downloadArtifact`, `agentRuns.submitLocalToolResult`, `agentRuns.runWithLocalTools` |
119
183
  | **Auth** | `login`, `logout`, `ensureToken`, `forceRefresh`, `discover`, `authorize`, `exchangeCode`, `refreshToken` |
120
- | **Models** | `listModels`, `listModelsWithStatus`, `getModelCapabilities`, `getQuotaSummary` |
184
+ | **Models** | `listModels`, `listModelsWithStatus`, `getModelCapabilities`, `getQuotaSummary`, `modelSupportsInputModality`, `modelSupportsImageInput`, `findFirstModelByInputModality`, `findDesktopVisualUnderstandingModel` |
121
185
  | **Skills** | `browseSkills`, `browseSkillsList`, `getSkillDetail`, `resolveSkill`, `installSkill`, `downloadSkill`, `uploadSkill`, `generateSkill`, `optimizeSkill`, `validateSkill` |
122
186
  | **Tools** | `listTools`, `getTool` |
123
187
  | **Wallet** | `getWalletStats`, `getWalletTransactions` |
@@ -166,6 +230,38 @@ const resp = await client.chat('claude-opus-4-7', {
166
230
 
167
231
  `AllowedDomains` / `BlockedDomains` 互斥,同时传入抛 `Error`。
168
232
 
233
+ ### 示例:桌面视觉理解 sidecar 选模型(CrabCode desktop automation / computer-use)
234
+
235
+ ```ts
236
+ import {
237
+ Client,
238
+ findDesktopVisualUnderstandingModel,
239
+ modelSupportsImageInput,
240
+ } from '@acosmi/sdk-ts';
241
+
242
+ const client = new Client({ serverURL: 'https://acosmi.com' });
243
+ const models = await client.listModels();
244
+
245
+ // 1) 主模型是否能直接吃截图?
246
+ const primaryCanSeeImages = modelSupportsImageInput(
247
+ models.find((m) => m.modelId === 'deepseek-v4') ?? null,
248
+ );
249
+
250
+ // 2) 不能 → 走桌面视觉 sidecar:截图先送 sidecar 解析为结构化 UI 描述,再喂主模型
251
+ const sidecar = findDesktopVisualUnderstandingModel(models);
252
+ if (!sidecar) {
253
+ throw new Error('No desktop visual understanding model available — 让管理员在网关启用一个 sidecar 模型');
254
+ }
255
+ console.log('sidecar →', sidecar.modelId);
256
+ ```
257
+
258
+ 红线:
259
+
260
+ - `ManagedModel.inputModalities` 用于客户端判断模型可接收的用户输入类型('text' | 'image')。
261
+ - `capabilities.supports_desktop_visual_understanding` 用于选择专门解析桌面截图的视觉 sidecar 模型,与 `inputModalities` 是正交两件事(普通视觉模型不一定擅长 UI 解析)。
262
+ - 客户端不应硬编码模型名做能力推断,应完全依赖 SDK catalog 字段。
263
+ - 上游未下发 `inputModalities` 时 SDK 保持 `undefined`,调用方必须保守按 text-only / unknown 处理。
264
+
169
265
  ### 示例:钱包 + 余额 + 流量包购买
170
266
 
171
267
  ```ts
@@ -206,6 +302,7 @@ const view = await client.getBugReport(result.feedback_id);
206
302
  | `HTTPError` | 4xx/5xx,含 `status` / `body` / `requestID` |
207
303
  | `NetworkError` | TCP/DNS/TLS 失败 |
208
304
  | `StreamError` | SSE 流解析失败 |
305
+ | `AgentRunStreamError` | Agent Runs 流返回 `error` 事件(默认抛出;可设 `throwOnError:false` 自行消费) |
209
306
  | `BusinessError` | 网关返回 `code !== 0`,含 `code` / `bizMsg` |
210
307
  | `RateLimitError` | 429(含 `retryAfter`) |
211
308
  | `OrderTerminalError` | `waitForPayment` 终态失败 |
@@ -249,7 +346,9 @@ npm run build
249
346
 
250
347
  | 版本 | 状态 | 概要 |
251
348
  | --- | --- | --- |
252
- | 1.0.1 | 当前稳定版 | 修复 1.0.0 双层 broken packaging:tsup 输出 `.mjs+.cjs` 与 exports 字段对齐;9 处 `declare module` 绑包名 `@acosmi/sdk-ts` 让 d.ts augmentation 在 consumer 视角合并;prepublishOnly 加 packed-tarball 烟测拦截"源码过 / 打包后 broken"。 |
349
+ | 1.1.0 | 当前稳定版 | 新增 SDK-facing `agentRuns` 网关客户端,覆盖 create/stream/cancel/get/artifacts/local-tool-result,并提供本地只读工具桥协议。 |
350
+ | 1.0.2 | 稳定版 | 修复多进程共享 token refresh rotation 竞态。 |
351
+ | 1.0.1 | 历史稳定版 | 修复 1.0.0 双层 broken packaging:tsup 输出 `.mjs+.cjs` 与 exports 字段对齐;9 处 `declare module` 绑包名 `@acosmi/sdk-ts` 让 d.ts augmentation 在 consumer 视角合并;prepublishOnly 加 packed-tarball 烟测拦截"源码过 / 打包后 broken"。 |
253
352
  | 1.0.0 | **deprecated** | 双层 broken:(1) `package.json.exports` 8 处 `.mjs` 引用与 tsup 默认 `.js+.cjs` 错位 → bun/Node ESM `Cannot find module`;(2) 9 处 `declare module` 用相对路径,consumer 视角断链 → 50+ 方法 TS2339。`npm install @acosmi/sdk-ts` 自动跳到 1.0.1。 |
254
353
 
255
354
  ## License