@acosmi/sdk-ts 1.0.2 → 1.1.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 +34 -0
- package/README.md +72 -5
- package/dist/browser/index.mjs +501 -3
- package/dist/browser/index.mjs.map +1 -1
- package/dist/index.mjs +501 -3
- package/dist/index.mjs.map +1 -1
- package/dist/node/adapters/anthropic.d.cts +1 -1
- package/dist/node/adapters/anthropic.d.ts +1 -1
- package/dist/node/adapters/openai.d.cts +1 -1
- package/dist/node/adapters/openai.d.ts +1 -1
- package/dist/node/{index-C3Z_84Bv.d.cts → index-BI8EgBXu.d.cts} +1 -1
- package/dist/node/{index-C3Z_84Bv.d.ts → index-BI8EgBXu.d.ts} +1 -1
- package/dist/node/index.cjs +502 -2
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +210 -7
- package/dist/node/index.d.ts +210 -7
- package/dist/node/index.mjs +501 -3
- package/dist/node/index.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ 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.1.0] — 2026-05-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Agent Runs SDK Gateway** — 新增 `client.agentRuns` namespace,作为 CrabDesign、CrabCode、CrabClaw 等下游产品接入 Acosmi 云端智能体循环的正式 SDK 协议边界:
|
|
13
|
+
- `create(req, signal?)`
|
|
14
|
+
- `stream(runId, opts?, signal?)`
|
|
15
|
+
- `run(req, opts?, signal?)`
|
|
16
|
+
- `cancel(runId, signal?)`
|
|
17
|
+
- `get(runId, signal?)`
|
|
18
|
+
- `listArtifacts(runId, signal?)`
|
|
19
|
+
- `downloadArtifact(runId, artifactId, signal?)`
|
|
20
|
+
- `submitLocalToolResult(runId, result, signal?)`
|
|
21
|
+
- `runWithLocalTools(req, handlers, opts?, signal?)`
|
|
22
|
+
|
|
23
|
+
- **Agent Run protocol types** — 新增 `AgentRunCreateRequest`、`AgentRunStreamEvent` discriminated union、`AgentRunArtifact`、`AgentRunStreamError` 等公开类型。SDK public API 使用 camelCase,HTTP wire-format 使用 snake_case。
|
|
24
|
+
|
|
25
|
+
- **Local tool bridge protocol** — SDK 不内置产品专属本地文件读取逻辑;`local_tool_request` 由下游处理,并通过 `submitLocalToolResult({ requestId, ok, content | error })` 返回。便捷封装 `runWithLocalTools` 支持 handler 超时、拒绝和取消。
|
|
26
|
+
|
|
27
|
+
- **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 等待点。
|
|
28
|
+
|
|
29
|
+
- **Exact usage settlement** — Agent Runs 结算只接受 provider/ADK 透传的 `exact: true` usage,并通过 tk-dist `SettlePrecise(input/output/cacheRead/cacheCreate)` 精算;若 provider 未返回精确 usage,服务端会释放 hold 并返回 `usage_missing_released`,不会用字符数或 token 估算扣费。
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **401 retry policy for Agent Runs** — Agent Runs 客户端只对 GET/stream/download 等安全查询做单次 401 refresh retry;`create`、`submitLocalToolResult` 等可能产生副作用的 POST 不自动重放,避免重复创建 run 或重复计费。
|
|
34
|
+
|
|
35
|
+
### Tests
|
|
36
|
+
|
|
37
|
+
- 新增 `test/agent-runs.test.ts`,覆盖 create 字段序列化、完整流事件解析、401 refresh 策略、error 事件结构化抛出、local tool result payload、artifact 下载文件名/content-type 解析。
|
|
38
|
+
- `scripts/smoke-pack.mjs` 增加 consumer 视角的 `client.agentRuns` 类型调用验证。
|
|
39
|
+
|
|
8
40
|
## [1.0.2] — 2026-05-06
|
|
9
41
|
|
|
10
42
|
### Fixed
|
|
@@ -96,5 +128,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
96
128
|
- 36/36 vitest 全绿,源码 typecheck/lint/build 0 错误
|
|
97
129
|
- 翻车机制:`prepublishOnly` 仅跑源码 typecheck/vitest/build,不验证 packed product 在 consumer 视角能否解析
|
|
98
130
|
|
|
131
|
+
[1.1.0]: https://github.com/acosmi/sdk-ts/releases/tag/v1.1.0
|
|
132
|
+
[1.0.2]: https://github.com/acosmi/sdk-ts/releases/tag/v1.0.2
|
|
99
133
|
[1.0.1]: https://github.com/acosmi/sdk-ts/releases/tag/v1.0.1
|
|
100
134
|
[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
|
[](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.
|
|
11
|
-
- 测试:
|
|
12
|
-
- 包链接:[npm](https://www.npmjs.com/package/@acosmi/sdk-ts/v/1.0
|
|
10
|
+
- 当前版本:**1.1.0**(新增 SDK-facing Agent Runs 公开 API;详见 [CHANGELOG](./CHANGELOG.md))
|
|
11
|
+
- 测试:56/56 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.1.0) · [tarball](https://registry.npmjs.org/@acosmi/sdk-ts/-/sdk-ts-1.1.0.tgz) · [GitHub Release](https://github.com/acosmi/sdk-ts/releases/tag/v1.1.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,6 +179,7 @@ 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
184
|
| **Models** | `listModels`, `listModelsWithStatus`, `getModelCapabilities`, `getQuotaSummary` |
|
|
121
185
|
| **Skills** | `browseSkills`, `browseSkillsList`, `getSkillDetail`, `resolveSkill`, `installSkill`, `downloadSkill`, `uploadSkill`, `generateSkill`, `optimizeSkill`, `validateSkill` |
|
|
@@ -206,6 +270,7 @@ const view = await client.getBugReport(result.feedback_id);
|
|
|
206
270
|
| `HTTPError` | 4xx/5xx,含 `status` / `body` / `requestID` |
|
|
207
271
|
| `NetworkError` | TCP/DNS/TLS 失败 |
|
|
208
272
|
| `StreamError` | SSE 流解析失败 |
|
|
273
|
+
| `AgentRunStreamError` | Agent Runs 流返回 `error` 事件(默认抛出;可设 `throwOnError:false` 自行消费) |
|
|
209
274
|
| `BusinessError` | 网关返回 `code !== 0`,含 `code` / `bizMsg` |
|
|
210
275
|
| `RateLimitError` | 429(含 `retryAfter`) |
|
|
211
276
|
| `OrderTerminalError` | `waitForPayment` 终态失败 |
|
|
@@ -249,7 +314,9 @@ npm run build
|
|
|
249
314
|
|
|
250
315
|
| 版本 | 状态 | 概要 |
|
|
251
316
|
| --- | --- | --- |
|
|
252
|
-
| 1.0
|
|
317
|
+
| 1.1.0 | 当前稳定版 | 新增 SDK-facing `agentRuns` 网关客户端,覆盖 create/stream/cancel/get/artifacts/local-tool-result,并提供本地只读工具桥协议。 |
|
|
318
|
+
| 1.0.2 | 稳定版 | 修复多进程共享 token refresh rotation 竞态。 |
|
|
319
|
+
| 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
320
|
| 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
321
|
|
|
255
322
|
## License
|
package/dist/browser/index.mjs
CHANGED
|
@@ -1972,8 +1972,25 @@ function extractAnthropicBlockMeta(eventType, data, blockTypeMap) {
|
|
|
1972
1972
|
}
|
|
1973
1973
|
}
|
|
1974
1974
|
|
|
1975
|
-
// src/
|
|
1976
|
-
|
|
1975
|
+
// src/agent-runs-types.ts
|
|
1976
|
+
var AgentRunStreamError = class extends Error {
|
|
1977
|
+
event;
|
|
1978
|
+
code;
|
|
1979
|
+
stage;
|
|
1980
|
+
retryable;
|
|
1981
|
+
constructor(event) {
|
|
1982
|
+
const err = event.error;
|
|
1983
|
+
super(err.stage ? `agent run failed: ${err.stage}: ${err.message}` : `agent run failed: ${err.message}`);
|
|
1984
|
+
this.name = "AgentRunStreamError";
|
|
1985
|
+
this.event = event;
|
|
1986
|
+
this.code = err.code ?? "";
|
|
1987
|
+
this.stage = err.stage ?? "";
|
|
1988
|
+
this.retryable = err.retryable ?? false;
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
|
|
1992
|
+
// src/client/agent-runs.ts
|
|
1993
|
+
init_types();
|
|
1977
1994
|
|
|
1978
1995
|
// src/client.ts
|
|
1979
1996
|
init_types();
|
|
@@ -3254,6 +3271,487 @@ async function sleep(ms, signal) {
|
|
|
3254
3271
|
});
|
|
3255
3272
|
}
|
|
3256
3273
|
|
|
3274
|
+
// src/client/agent-runs.ts
|
|
3275
|
+
var agentRunsByClient = /* @__PURE__ */ new WeakMap();
|
|
3276
|
+
Object.defineProperty(Client.prototype, "agentRuns", {
|
|
3277
|
+
configurable: true,
|
|
3278
|
+
enumerable: false,
|
|
3279
|
+
get() {
|
|
3280
|
+
let existing = agentRunsByClient.get(this);
|
|
3281
|
+
if (!existing) {
|
|
3282
|
+
existing = new AgentRunsClient(this);
|
|
3283
|
+
agentRunsByClient.set(this, existing);
|
|
3284
|
+
}
|
|
3285
|
+
return existing;
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
3288
|
+
var AgentRunsClient = class {
|
|
3289
|
+
constructor(client) {
|
|
3290
|
+
this.client = client;
|
|
3291
|
+
}
|
|
3292
|
+
client;
|
|
3293
|
+
async create(req, signal) {
|
|
3294
|
+
const resp = await this.requestAPI(
|
|
3295
|
+
"POST",
|
|
3296
|
+
"/agent-runs",
|
|
3297
|
+
toWireCreateRequest(req),
|
|
3298
|
+
signal,
|
|
3299
|
+
{ retryOn401: false }
|
|
3300
|
+
);
|
|
3301
|
+
return fromWireCreateResponse(resp);
|
|
3302
|
+
}
|
|
3303
|
+
get(runId, signal) {
|
|
3304
|
+
return this.requestAPI(
|
|
3305
|
+
"GET",
|
|
3306
|
+
`/agent-runs/${encodeURIComponent(runId)}`,
|
|
3307
|
+
null,
|
|
3308
|
+
signal,
|
|
3309
|
+
{ retryOn401: true }
|
|
3310
|
+
).then(fromWireRun);
|
|
3311
|
+
}
|
|
3312
|
+
stream(runId, opts = {}, signal) {
|
|
3313
|
+
return {
|
|
3314
|
+
[Symbol.asyncIterator]: () => this.streamGen(runId, opts, signal)
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
cancel(runId, signal) {
|
|
3318
|
+
return this.requestAPI(
|
|
3319
|
+
"POST",
|
|
3320
|
+
`/agent-runs/${encodeURIComponent(runId)}/cancel`,
|
|
3321
|
+
{},
|
|
3322
|
+
signal,
|
|
3323
|
+
{ retryOn401: false }
|
|
3324
|
+
).then(fromWireRun);
|
|
3325
|
+
}
|
|
3326
|
+
listArtifacts(runId, signal) {
|
|
3327
|
+
return this.requestAPI(
|
|
3328
|
+
"GET",
|
|
3329
|
+
`/agent-runs/${encodeURIComponent(runId)}/artifacts`,
|
|
3330
|
+
null,
|
|
3331
|
+
signal,
|
|
3332
|
+
{ retryOn401: true }
|
|
3333
|
+
).then((r) => (r.artifacts ?? []).map(fromWireArtifact));
|
|
3334
|
+
}
|
|
3335
|
+
async downloadArtifact(runId, artifactId, signal) {
|
|
3336
|
+
const resp = await this.requestRaw(
|
|
3337
|
+
"GET",
|
|
3338
|
+
`/agent-runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}`,
|
|
3339
|
+
null,
|
|
3340
|
+
signal,
|
|
3341
|
+
{ retryOn401: true }
|
|
3342
|
+
);
|
|
3343
|
+
const contentType = resp.headers.get("Content-Type") ?? void 0;
|
|
3344
|
+
const filename = filenameFromContentDisposition(resp.headers.get("Content-Disposition")) ?? artifactId;
|
|
3345
|
+
const data = await readLimited(resp.body, maxDownloadSize);
|
|
3346
|
+
return { data, filename, contentType };
|
|
3347
|
+
}
|
|
3348
|
+
submitLocalToolResult(runId, result, signal) {
|
|
3349
|
+
return this.requestAPI(
|
|
3350
|
+
"POST",
|
|
3351
|
+
`/agent-runs/${encodeURIComponent(runId)}/local-tool-results`,
|
|
3352
|
+
toWireLocalToolResult(result),
|
|
3353
|
+
signal,
|
|
3354
|
+
{ retryOn401: false }
|
|
3355
|
+
).then(fromWireRun);
|
|
3356
|
+
}
|
|
3357
|
+
run(req, opts = {}, signal) {
|
|
3358
|
+
return {
|
|
3359
|
+
[Symbol.asyncIterator]: () => this.runGen(req, opts, signal)
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3362
|
+
runWithLocalTools(req, handlers, opts = {}, signal) {
|
|
3363
|
+
return {
|
|
3364
|
+
[Symbol.asyncIterator]: () => this.runWithLocalToolsGen(req, handlers, opts, signal)
|
|
3365
|
+
};
|
|
3366
|
+
}
|
|
3367
|
+
async *runGen(req, opts, signal) {
|
|
3368
|
+
const created = await this.create(req, signal);
|
|
3369
|
+
yield* this.stream(created.runId, opts, signal);
|
|
3370
|
+
}
|
|
3371
|
+
async *runWithLocalToolsGen(req, handlers, opts, signal) {
|
|
3372
|
+
let currentRunId = "";
|
|
3373
|
+
for await (const event of this.run(req, opts, signal)) {
|
|
3374
|
+
if (event.type === "run_started") {
|
|
3375
|
+
currentRunId = event.runId;
|
|
3376
|
+
}
|
|
3377
|
+
if (opts.onEvent) await opts.onEvent(event);
|
|
3378
|
+
let localToolTask;
|
|
3379
|
+
if (event.type === "local_tool_request") {
|
|
3380
|
+
if (currentRunId === "") {
|
|
3381
|
+
throw new Error("local tool request arrived before run_started");
|
|
3382
|
+
}
|
|
3383
|
+
localToolTask = this.invokeLocalTool(currentRunId, event, handlers, opts.timeoutMs, signal).then(async (result) => {
|
|
3384
|
+
await this.submitLocalToolResult(currentRunId, result, signal);
|
|
3385
|
+
});
|
|
3386
|
+
}
|
|
3387
|
+
yield event;
|
|
3388
|
+
if (localToolTask) await localToolTask;
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
async invokeLocalTool(runId, event, handlers, timeoutMs = 3e4, signal) {
|
|
3392
|
+
const handler = handlers[event.name];
|
|
3393
|
+
if (!handler) {
|
|
3394
|
+
return {
|
|
3395
|
+
requestId: event.requestId,
|
|
3396
|
+
ok: false,
|
|
3397
|
+
error: `local tool rejected: no handler for ${event.name}`
|
|
3398
|
+
};
|
|
3399
|
+
}
|
|
3400
|
+
const ctl = new AbortController();
|
|
3401
|
+
const timer = setTimeout(() => ctl.abort(), timeoutMs);
|
|
3402
|
+
let parentAbort;
|
|
3403
|
+
if (signal) {
|
|
3404
|
+
if (signal.aborted) ctl.abort();
|
|
3405
|
+
else {
|
|
3406
|
+
parentAbort = () => ctl.abort();
|
|
3407
|
+
signal.addEventListener("abort", parentAbort);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
try {
|
|
3411
|
+
const content = await handler(event.input, {
|
|
3412
|
+
runId,
|
|
3413
|
+
requestId: event.requestId,
|
|
3414
|
+
name: event.name,
|
|
3415
|
+
signal: ctl.signal
|
|
3416
|
+
});
|
|
3417
|
+
return { requestId: event.requestId, ok: true, content };
|
|
3418
|
+
} catch (e) {
|
|
3419
|
+
if (signal?.aborted) throw e;
|
|
3420
|
+
const timedOut = ctl.signal.aborted;
|
|
3421
|
+
return {
|
|
3422
|
+
requestId: event.requestId,
|
|
3423
|
+
ok: false,
|
|
3424
|
+
error: timedOut ? `local tool timed out after ${timeoutMs}ms` : errorMessage(e)
|
|
3425
|
+
};
|
|
3426
|
+
} finally {
|
|
3427
|
+
clearTimeout(timer);
|
|
3428
|
+
if (parentAbort && signal) signal.removeEventListener("abort", parentAbort);
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
async *streamGen(runId, opts, signal) {
|
|
3432
|
+
const resp = await this.requestRaw(
|
|
3433
|
+
"GET",
|
|
3434
|
+
`/agent-runs/${encodeURIComponent(runId)}/stream`,
|
|
3435
|
+
null,
|
|
3436
|
+
signal,
|
|
3437
|
+
{ retryOn401: true, accept: "text/event-stream" }
|
|
3438
|
+
);
|
|
3439
|
+
if (!resp.body) {
|
|
3440
|
+
throw new Error("agent run stream: empty response body");
|
|
3441
|
+
}
|
|
3442
|
+
for await (const event of readAgentRunEvents(resp.body)) {
|
|
3443
|
+
if (event.type === "error" && opts.throwOnError !== false) {
|
|
3444
|
+
throw new AgentRunStreamError(event);
|
|
3445
|
+
}
|
|
3446
|
+
yield event;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
async requestAPI(method, path, body, signal, opts) {
|
|
3450
|
+
const resp = await this.requestRaw(method, path, body, signal, opts);
|
|
3451
|
+
const text = await resp.text();
|
|
3452
|
+
const result = JSON.parse(text);
|
|
3453
|
+
const bizErr = apiResponseBusinessError(result);
|
|
3454
|
+
if (bizErr) throw bizErr;
|
|
3455
|
+
return result.data;
|
|
3456
|
+
}
|
|
3457
|
+
async requestRaw(method, path, body, signal, opts, retried = false) {
|
|
3458
|
+
const token = await this.client.ensureToken(signal);
|
|
3459
|
+
const url = this.client.apiURL(path);
|
|
3460
|
+
const headers = {
|
|
3461
|
+
Authorization: `Bearer ${token}`,
|
|
3462
|
+
Accept: opts.accept ?? "application/json"
|
|
3463
|
+
};
|
|
3464
|
+
let bodyStr;
|
|
3465
|
+
if (body != null) {
|
|
3466
|
+
bodyStr = typeof body === "string" ? body : JSON.stringify(body);
|
|
3467
|
+
headers["Content-Type"] = "application/json";
|
|
3468
|
+
}
|
|
3469
|
+
const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
|
|
3470
|
+
if (resp.status === 401 && opts.retryOn401 && !retried) {
|
|
3471
|
+
try {
|
|
3472
|
+
await resp.body?.cancel();
|
|
3473
|
+
} catch {
|
|
3474
|
+
}
|
|
3475
|
+
await this.client.forceRefresh(signal);
|
|
3476
|
+
return this.requestRaw(method, path, body, signal, opts, true);
|
|
3477
|
+
}
|
|
3478
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
3479
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
3480
|
+
throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
3481
|
+
}
|
|
3482
|
+
return resp;
|
|
3483
|
+
}
|
|
3484
|
+
};
|
|
3485
|
+
function toWireCreateRequest(req) {
|
|
3486
|
+
return {
|
|
3487
|
+
app_id: req.appId,
|
|
3488
|
+
mode: req.mode,
|
|
3489
|
+
session_id: req.sessionId,
|
|
3490
|
+
input: req.input,
|
|
3491
|
+
messages: req.messages,
|
|
3492
|
+
model: req.model,
|
|
3493
|
+
active_skill_ids: req.activeSkillIds,
|
|
3494
|
+
knowledge_base_ids: req.knowledgeBaseIds,
|
|
3495
|
+
metadata: req.metadata,
|
|
3496
|
+
local_context_policy: req.localContextPolicy ? {
|
|
3497
|
+
enabled: req.localContextPolicy.enabled,
|
|
3498
|
+
readonly: req.localContextPolicy.readonly,
|
|
3499
|
+
max_bytes: req.localContextPolicy.maxBytes,
|
|
3500
|
+
allowed_tools: req.localContextPolicy.allowedTools
|
|
3501
|
+
} : void 0,
|
|
3502
|
+
artifact_policy: req.artifactPolicy ? {
|
|
3503
|
+
enabled: req.artifactPolicy.enabled,
|
|
3504
|
+
max_files: req.artifactPolicy.maxFiles
|
|
3505
|
+
} : void 0
|
|
3506
|
+
};
|
|
3507
|
+
}
|
|
3508
|
+
function toWireLocalToolResult(result) {
|
|
3509
|
+
return {
|
|
3510
|
+
request_id: result.requestId,
|
|
3511
|
+
ok: result.ok,
|
|
3512
|
+
content: result.content,
|
|
3513
|
+
error: result.error
|
|
3514
|
+
};
|
|
3515
|
+
}
|
|
3516
|
+
function fromWireCreateResponse(resp) {
|
|
3517
|
+
return {
|
|
3518
|
+
runId: resp.run_id ?? "",
|
|
3519
|
+
sessionId: resp.session_id ?? "",
|
|
3520
|
+
status: toStatus(resp.status)
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3523
|
+
function fromWireRun(resp) {
|
|
3524
|
+
return {
|
|
3525
|
+
runId: resp.run_id ?? "",
|
|
3526
|
+
sessionId: resp.session_id ?? "",
|
|
3527
|
+
appId: resp.app_id,
|
|
3528
|
+
mode: resp.mode,
|
|
3529
|
+
status: toStatus(resp.status),
|
|
3530
|
+
createdAt: resp.created_at,
|
|
3531
|
+
startedAt: resp.started_at,
|
|
3532
|
+
completedAt: resp.completed_at,
|
|
3533
|
+
error: normalizeError(resp.error),
|
|
3534
|
+
metadata: resp.metadata
|
|
3535
|
+
};
|
|
3536
|
+
}
|
|
3537
|
+
function fromWireArtifact(resp) {
|
|
3538
|
+
return {
|
|
3539
|
+
id: resp.id ?? resp.artifact_id ?? "",
|
|
3540
|
+
filename: resp.filename ?? resp.name ?? resp.id ?? resp.artifact_id ?? "artifact",
|
|
3541
|
+
contentType: resp.content_type ?? resp.mime_type,
|
|
3542
|
+
size: typeof resp.size === "number" ? resp.size : void 0,
|
|
3543
|
+
type: resp.type,
|
|
3544
|
+
metadata: resp.metadata
|
|
3545
|
+
};
|
|
3546
|
+
}
|
|
3547
|
+
async function* readAgentRunEvents(body) {
|
|
3548
|
+
let eventName = "";
|
|
3549
|
+
let dataLines = [];
|
|
3550
|
+
const flush = () => {
|
|
3551
|
+
if (dataLines.length === 0) return null;
|
|
3552
|
+
const data = dataLines.join("\n");
|
|
3553
|
+
dataLines = [];
|
|
3554
|
+
if (data === "[DONE]") return null;
|
|
3555
|
+
return parseAgentRunEvent(eventName, data);
|
|
3556
|
+
};
|
|
3557
|
+
for await (const line of iterSSELines(body)) {
|
|
3558
|
+
if (line === "") {
|
|
3559
|
+
const event2 = flush();
|
|
3560
|
+
eventName = "";
|
|
3561
|
+
if (event2) yield event2;
|
|
3562
|
+
continue;
|
|
3563
|
+
}
|
|
3564
|
+
if (line.startsWith(":")) continue;
|
|
3565
|
+
if (line.startsWith("event:")) {
|
|
3566
|
+
eventName = line.slice("event:".length).trim();
|
|
3567
|
+
continue;
|
|
3568
|
+
}
|
|
3569
|
+
if (line.startsWith("data:")) {
|
|
3570
|
+
dataLines.push(line.slice("data:".length).trimStart());
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
const event = flush();
|
|
3574
|
+
if (event) yield event;
|
|
3575
|
+
}
|
|
3576
|
+
function parseAgentRunEvent(eventName, data) {
|
|
3577
|
+
const payload = JSON.parse(data);
|
|
3578
|
+
const obj = isRecord(payload) ? payload : { type: eventName, data: payload };
|
|
3579
|
+
const type = stringField(obj, "type") || eventName;
|
|
3580
|
+
switch (type) {
|
|
3581
|
+
case "run_started":
|
|
3582
|
+
return {
|
|
3583
|
+
type: "run_started",
|
|
3584
|
+
runId: stringField(obj, "run_id", "runId"),
|
|
3585
|
+
sessionId: stringField(obj, "session_id", "sessionId")
|
|
3586
|
+
};
|
|
3587
|
+
case "status":
|
|
3588
|
+
return {
|
|
3589
|
+
type: "status",
|
|
3590
|
+
status: stringField(obj, "status"),
|
|
3591
|
+
message: optionalStringField(obj, "message")
|
|
3592
|
+
};
|
|
3593
|
+
case "text_delta":
|
|
3594
|
+
return { type: "text_delta", text: stringField(obj, "text") };
|
|
3595
|
+
case "reasoning_delta":
|
|
3596
|
+
return { type: "reasoning_delta", text: stringField(obj, "text") };
|
|
3597
|
+
case "tool_call":
|
|
3598
|
+
return {
|
|
3599
|
+
type: "tool_call",
|
|
3600
|
+
id: stringField(obj, "id"),
|
|
3601
|
+
name: stringField(obj, "name"),
|
|
3602
|
+
input: obj.input
|
|
3603
|
+
};
|
|
3604
|
+
case "tool_result":
|
|
3605
|
+
return {
|
|
3606
|
+
type: "tool_result",
|
|
3607
|
+
id: stringField(obj, "id"),
|
|
3608
|
+
name: optionalStringField(obj, "name"),
|
|
3609
|
+
result: obj.result,
|
|
3610
|
+
error: optionalStringField(obj, "error")
|
|
3611
|
+
};
|
|
3612
|
+
case "local_tool_request":
|
|
3613
|
+
return {
|
|
3614
|
+
type: "local_tool_request",
|
|
3615
|
+
requestId: stringField(obj, "request_id", "requestId"),
|
|
3616
|
+
name: stringField(obj, "name"),
|
|
3617
|
+
input: obj.input
|
|
3618
|
+
};
|
|
3619
|
+
case "artifact":
|
|
3620
|
+
return {
|
|
3621
|
+
type: "artifact",
|
|
3622
|
+
artifact: fromWireArtifact(isRecord(obj.artifact) ? obj.artifact : obj)
|
|
3623
|
+
};
|
|
3624
|
+
case "sources":
|
|
3625
|
+
return { type: "sources", sources: obj.sources };
|
|
3626
|
+
case "usage":
|
|
3627
|
+
return {
|
|
3628
|
+
type: "usage",
|
|
3629
|
+
usage: normalizeUsage(isRecord(obj.usage) ? obj.usage : obj)
|
|
3630
|
+
};
|
|
3631
|
+
case "settle":
|
|
3632
|
+
return {
|
|
3633
|
+
type: "settle",
|
|
3634
|
+
settlement: normalizeSettlement(isRecord(obj.settlement) ? obj.settlement : obj)
|
|
3635
|
+
};
|
|
3636
|
+
case "error":
|
|
3637
|
+
return { type: "error", error: normalizeError(obj.error) ?? normalizeError(obj) };
|
|
3638
|
+
case "done":
|
|
3639
|
+
return {
|
|
3640
|
+
type: "done",
|
|
3641
|
+
runId: stringField(obj, "run_id", "runId"),
|
|
3642
|
+
status: stringField(obj, "status")
|
|
3643
|
+
};
|
|
3644
|
+
default:
|
|
3645
|
+
return {
|
|
3646
|
+
type: "error",
|
|
3647
|
+
error: {
|
|
3648
|
+
code: "unknown_event",
|
|
3649
|
+
message: `unknown agent run event: ${type}`,
|
|
3650
|
+
raw: obj
|
|
3651
|
+
}
|
|
3652
|
+
};
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
function normalizeUsage(value) {
|
|
3656
|
+
return {
|
|
3657
|
+
...value,
|
|
3658
|
+
inputTokens: numberField(value, "input_tokens", "inputTokens"),
|
|
3659
|
+
outputTokens: numberField(value, "output_tokens", "outputTokens"),
|
|
3660
|
+
totalTokens: numberField(value, "total_tokens", "totalTokens"),
|
|
3661
|
+
cacheReadTokens: numberField(value, "cache_read_tokens", "cacheReadTokens"),
|
|
3662
|
+
cacheCreateTokens: numberField(value, "cache_create_tokens", "cacheCreateTokens"),
|
|
3663
|
+
exact: booleanField(value, "exact"),
|
|
3664
|
+
source: optionalStringField(value, "source")
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
function normalizeSettlement(value) {
|
|
3668
|
+
return {
|
|
3669
|
+
...value,
|
|
3670
|
+
requestId: optionalStringField(value, "request_id", "requestId"),
|
|
3671
|
+
status: optionalStringField(value, "status"),
|
|
3672
|
+
consumeStatus: optionalStringField(value, "consume_status", "consumeStatus"),
|
|
3673
|
+
inputTokens: numberField(value, "input_tokens", "inputTokens"),
|
|
3674
|
+
outputTokens: numberField(value, "output_tokens", "outputTokens"),
|
|
3675
|
+
totalTokens: numberField(value, "total_tokens", "totalTokens"),
|
|
3676
|
+
cacheReadTokens: numberField(value, "cache_read_tokens", "cacheReadTokens"),
|
|
3677
|
+
cacheCreateTokens: numberField(value, "cache_create_tokens", "cacheCreateTokens"),
|
|
3678
|
+
tokenRemaining: numberField(value, "token_remaining", "tokenRemaining"),
|
|
3679
|
+
callRemaining: numberField(value, "call_remaining", "callRemaining"),
|
|
3680
|
+
retryQueued: booleanField(value, "retry_queued", "retryQueued"),
|
|
3681
|
+
exact: booleanField(value, "exact")
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
function normalizeError(value) {
|
|
3685
|
+
if (value == null) return void 0;
|
|
3686
|
+
if (typeof value === "string") return { message: value, raw: value };
|
|
3687
|
+
if (!isRecord(value)) return { message: String(value), raw: value };
|
|
3688
|
+
return {
|
|
3689
|
+
code: optionalStringField(value, "code", "error_code", "errorCode"),
|
|
3690
|
+
message: stringField(value, "message", "error") || "agent run failed",
|
|
3691
|
+
stage: optionalStringField(value, "stage"),
|
|
3692
|
+
retryable: typeof value.retryable === "boolean" ? value.retryable : void 0,
|
|
3693
|
+
raw: value
|
|
3694
|
+
};
|
|
3695
|
+
}
|
|
3696
|
+
function toStatus(status) {
|
|
3697
|
+
switch (status) {
|
|
3698
|
+
case "running":
|
|
3699
|
+
case "completed":
|
|
3700
|
+
case "failed":
|
|
3701
|
+
case "cancelled":
|
|
3702
|
+
return status;
|
|
3703
|
+
default:
|
|
3704
|
+
return "queued";
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
function isRecord(value) {
|
|
3708
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
3709
|
+
}
|
|
3710
|
+
function stringField(obj, ...keys) {
|
|
3711
|
+
for (const key of keys) {
|
|
3712
|
+
const value = obj[key];
|
|
3713
|
+
if (typeof value === "string") return value;
|
|
3714
|
+
}
|
|
3715
|
+
return "";
|
|
3716
|
+
}
|
|
3717
|
+
function optionalStringField(obj, ...keys) {
|
|
3718
|
+
const value = stringField(obj, ...keys);
|
|
3719
|
+
return value === "" ? void 0 : value;
|
|
3720
|
+
}
|
|
3721
|
+
function numberField(obj, ...keys) {
|
|
3722
|
+
for (const key of keys) {
|
|
3723
|
+
const value = obj[key];
|
|
3724
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3725
|
+
}
|
|
3726
|
+
return void 0;
|
|
3727
|
+
}
|
|
3728
|
+
function booleanField(obj, ...keys) {
|
|
3729
|
+
for (const key of keys) {
|
|
3730
|
+
const value = obj[key];
|
|
3731
|
+
if (typeof value === "boolean") return value;
|
|
3732
|
+
}
|
|
3733
|
+
return void 0;
|
|
3734
|
+
}
|
|
3735
|
+
function filenameFromContentDisposition(value) {
|
|
3736
|
+
if (!value) return null;
|
|
3737
|
+
const utf8 = /filename\*=UTF-8''([^;]+)/i.exec(value);
|
|
3738
|
+
if (utf8?.[1]) {
|
|
3739
|
+
try {
|
|
3740
|
+
return decodeURIComponent(utf8[1]);
|
|
3741
|
+
} catch {
|
|
3742
|
+
return utf8[1];
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
const plain = /filename="?([^";]+)"?/i.exec(value);
|
|
3746
|
+
return plain?.[1] ?? null;
|
|
3747
|
+
}
|
|
3748
|
+
function errorMessage(e) {
|
|
3749
|
+
return e instanceof Error ? e.message : String(e);
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// src/index.ts
|
|
3753
|
+
init_betas();
|
|
3754
|
+
|
|
3257
3755
|
// src/client/entitlements.ts
|
|
3258
3756
|
Client.prototype.getBalance = async function(signal) {
|
|
3259
3757
|
const resp = await this.doJSON(
|
|
@@ -4078,6 +4576,6 @@ Client.prototype.getBugReport = async function(bugID, signal) {
|
|
|
4078
4576
|
return resp.data;
|
|
4079
4577
|
};
|
|
4080
4578
|
|
|
4081
|
-
export { AnthropicAdapter, BucketClassCommercial, BucketClassGeneric, BusinessError, Client, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBrowserOpen, ErrDiscovery, ErrRegistration, ErrSSLProxy, ErrTimeout, ErrTokenExchange, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OpenAIAdapter, OrderTerminalError, ProviderFormat, RateLimitError, ScopeAI, ScopeAccount, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, commerceScopes, computeBackoff, defaultRetryable, defaultSafeToRetry, discover, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, getAdapter, getAdapterForModel, isSSLError, modelScopes, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, parseNotificationEvent, parseSettlement, parseSourcesEvent, refreshToken, register, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge };
|
|
4579
|
+
export { AgentRunStreamError, AgentRunsClient, AnthropicAdapter, BucketClassCommercial, BucketClassGeneric, BusinessError, Client, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBrowserOpen, ErrDiscovery, ErrRegistration, ErrSSLProxy, ErrTimeout, ErrTokenExchange, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OpenAIAdapter, OrderTerminalError, ProviderFormat, RateLimitError, ScopeAI, ScopeAccount, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, commerceScopes, computeBackoff, defaultRetryable, defaultSafeToRetry, discover, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, getAdapter, getAdapterForModel, isSSLError, modelScopes, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, parseNotificationEvent, parseSettlement, parseSourcesEvent, refreshToken, register, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge };
|
|
4082
4580
|
//# sourceMappingURL=index.mjs.map
|
|
4083
4581
|
//# sourceMappingURL=index.mjs.map
|