@blade-hq/agent-client 2608.0.5-alpha.1 → 2608.0.5-beta.1
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/README.md +3 -121
- package/dist/index.d.ts +5 -6
- package/dist/index.js +56 -179
- package/dist/index.js.map +1 -1
- package/dist/resources/auth.d.ts +0 -26
- package/dist/resources/models.d.ts +0 -22
- package/dist/resources/sessions.d.ts +3 -5
- package/dist/schemas/message-utils.d.ts +1 -11
- package/dist/schemas/session.d.ts +1 -18
- package/dist/session/agent-session.d.ts +1 -21
- package/dist/session/state.d.ts +1 -14
- package/dist/shared/projection/helpers.d.ts +0 -8
- package/package.json +4 -2
- package/public-api.md +4 -82
package/README.md
CHANGED
|
@@ -76,15 +76,6 @@ await client.auth.getProviders() // 服务端支持的登录方式
|
|
|
76
76
|
|
|
77
77
|
`login()` 失败时的错误都带中文原因:弹窗被拦截、窗口被关闭、超时。
|
|
78
78
|
|
|
79
|
-
令牌要留在自己的服务端时,浏览器只把授权回调拿到的一次性 code 交给后端,由后端换:
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
// ExchangeCodeParams -> ExchangeCodeResult
|
|
83
|
-
const { access_token } = await client.auth.exchangeCode({ code, state, clientOrigin })
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
`clientOrigin` 要和发起授权时用的 origin 一致;服务端调用会自动补 `Origin` 头。
|
|
87
|
-
|
|
88
79
|
## 会话:client.sessions
|
|
89
80
|
|
|
90
81
|
### 实时对话(推荐入口)
|
|
@@ -139,73 +130,6 @@ await client.sessions.deleteSession(id)
|
|
|
139
130
|
await client.sessions.getSessionTurns(id) // 历史消息(投影格式,与实时流同构)
|
|
140
131
|
```
|
|
141
132
|
|
|
142
|
-
### 会话回放(演示 / 彩排)
|
|
143
|
-
|
|
144
|
-
拿一个已经聊完的会话当素材,重现当时的回复和工具调用,**完全不调用模型**。
|
|
145
|
-
用来做演示和彩排:离线可跑、不花钱、不会临场翻车。
|
|
146
|
-
|
|
147
|
-
**它不是把现有会话切成回放模式,而是派生一个新会话**,源会话原样不动:
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
// 1. 能不能拿它当素材(有并行子智能体、运行快照不完整的不行)
|
|
151
|
-
const { supported, reason } = await client.sessions.getReplayPreview(sourceId)
|
|
152
|
-
if (!supported) return show(reason) // reason 可直接展示给用户
|
|
153
|
-
|
|
154
|
-
// 2. 派生回放会话——这一步才是"进入回放",返回的是一个全新的 session_id
|
|
155
|
-
const { session_id: replayId } = await client.sessions.startReplaySession(sourceId)
|
|
156
|
-
const fast = await client.sessions.startReplaySession(sourceId, 2) // 或显式 1 | 2 | 5
|
|
157
|
-
|
|
158
|
-
// 3. 连上它,一出生就带着 replay 状态
|
|
159
|
-
const session = await client.sessions.connect(replayId)
|
|
160
|
-
session.getState().replay
|
|
161
|
-
// → { isReplay: true, speed: 5, sourceSessionId: sourceId }
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
不传倍速时用 `DEFAULT_REPLAY_SPEED`;所有创建入口都该用它,免得同一个源对话
|
|
165
|
-
从不同入口开出来速度不一样。
|
|
166
|
-
|
|
167
|
-
**连上之后不会自动播——它跟用户对台词**(下面的 `session` 都是第 3 步连上的**回放会话**):
|
|
168
|
-
|
|
169
|
-
```ts
|
|
170
|
-
// 源会话当初第一句问的是"帮我查下当前目录"
|
|
171
|
-
await session.send("帮我查下当前目录") // 对得上:按倍速重现当时的回复和工具调用
|
|
172
|
-
await session.send("今天天气怎么样") // 对不上:抛 replayMismatch 等你决定(见下)
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**回放中的状态和动作**都挂在会话上,和 `send()` 同级:
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
session.getState().replay // { isReplay, speed, sourceSessionId } | null(不是回放会话)
|
|
179
|
-
session.getState().viewerRole // "viewer" 表示只读,改不动回放
|
|
180
|
-
await session.setReplaySpeed(2)
|
|
181
|
-
await session.exitReplay() // 退出回放,之后的对话真的运行
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
改回放是 owner 专属(服务端 `PATCH` 走 owner 校验),只读身份下这两个动作是 no-op。
|
|
185
|
-
|
|
186
|
-
`replay` 是 `SessionState` 的一部分,跟着快照订阅走——Vue 直接接 `shallowRef` 即可,
|
|
187
|
-
不用自己拉状态:
|
|
188
|
-
|
|
189
|
-
```ts
|
|
190
|
-
const state = shallowRef(session.getState()) // session = connect(replayId) 的返回值
|
|
191
|
-
session.subscribe(() => (state.value = session.getState()))
|
|
192
|
-
// 模板里 state.value.replay?.isReplay / state.value.replay?.speed
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
连接会话时会一并拉好初始回放状态,所以第一帧就知道自己在不在回放。
|
|
196
|
-
|
|
197
|
-
**输入冲突**:用户说的话和录制内容对不上时,服务端会推 `replayMismatch`,必须在事件里给出决定:
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
session.on("replayMismatch", ({ expectedMessage, actualMessage, respond }) => {
|
|
201
|
-
respond("keep_replay") // 按录制内容继续
|
|
202
|
-
// respond("continue_replay") // 从这里开始真的运行
|
|
203
|
-
})
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
`replayMismatch` **只交给最先注册的处理器**;一个都没注册时默认 `continue_replay`
|
|
207
|
-
(静默转为真实运行)。React 应用可直接用 `@blade-hq/agent-react` 的 `useReplay()`。
|
|
208
|
-
|
|
209
133
|
### 工作区文件
|
|
210
134
|
|
|
211
135
|
```ts
|
|
@@ -227,26 +151,10 @@ await chat.downloadFile("输出/简历.md", "简历.md") // 浏览器下载
|
|
|
227
151
|
### 模型目录
|
|
228
152
|
|
|
229
153
|
```ts
|
|
230
|
-
const { default: defaultModel, models
|
|
231
|
-
// models: Array<{ id, label
|
|
232
|
-
// baseUrl: 平台默认模型服务的 OpenAI 兼容地址,自建应用带用户令牌可直接调;
|
|
233
|
-
// 各部署端口不同,别写死,老版本 Server 返回空串。
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**建会话选模型用 `default` / `id`,直接调 `baseUrl` 用 `defaultServiceModel` / `serviceModelId`。**
|
|
237
|
-
两套名字不通用:`id` 是平台内部标识,平台接了多个模型服务时形如
|
|
238
|
-
`provider-xxx::deepseek-v4-flash`,拿它去调 `baseUrl` 只会得到「模型不存在」。
|
|
239
|
-
`serviceModelId` 为空串表示这个模型不在 `baseUrl` 那个服务上,做模型选择器时按它过滤。
|
|
240
|
-
|
|
241
|
-
```ts
|
|
242
|
-
// 自己调模型服务
|
|
243
|
-
const body = { model: defaultServiceModel, messages, stream: true }
|
|
154
|
+
const { default: defaultModel, models } = await client.models.list()
|
|
155
|
+
// models: Array<{ id, label }>
|
|
244
156
|
```
|
|
245
157
|
|
|
246
|
-
`baseUrl` 是**服务端视角**的地址。平台常配成 `http://127.0.0.1:30000/v1`——从自己后端转发
|
|
247
|
-
没问题,直接交给浏览器就指向用户自己的机器了。默认形态是后端透传(密钥本来也不该进浏览器),
|
|
248
|
-
浏览器直连只适合这个地址对浏览器同样可达的场景。
|
|
249
|
-
|
|
250
158
|
## AgentSession
|
|
251
159
|
|
|
252
160
|
一个会话的实时状态机。**状态归属实例**:同一页面建多个会话互不干扰。
|
|
@@ -263,8 +171,6 @@ chat.getState()
|
|
|
263
171
|
// mode, "planning" | "executing" | null
|
|
264
172
|
// connection, 连接状态:"connected" | "connecting" | "reconnecting" | "disconnected"
|
|
265
173
|
// errorMessage, 最近一次运行错误
|
|
266
|
-
// replay, 回放状态:{ isReplay, speed, sourceSessionId } | null
|
|
267
|
-
// viewerRole, "owner" | "viewer" | null(只读身份改不动会话)
|
|
268
174
|
// turns, askAnswers, agentLoops, activeCompaction 进阶字段
|
|
269
175
|
// }
|
|
270
176
|
|
|
@@ -459,29 +365,6 @@ function Message({ message }: { message: ChatMessage }) {
|
|
|
459
365
|
}
|
|
460
366
|
```
|
|
461
367
|
|
|
462
|
-
### 让用户挑一个技能来做事
|
|
463
|
-
|
|
464
|
-
自己实现技能选择器时,用 `transformSlashCommand` 把选中的技能翻译成智能体能执行的一段话:
|
|
465
|
-
|
|
466
|
-
```ts
|
|
467
|
-
import { transformSlashCommand, type SkillMentionAvailability } from "@blade-hq/agent-client"
|
|
468
|
-
|
|
469
|
-
transformSlashCommand("org/data-analysis", "分析这份季度报表")
|
|
470
|
-
// "请使用 org/data-analysis skill 完成任务\n分析这份季度报表"
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
第三个参数说明这个技能眼下能不能直接用。技能装没装、加载没加载,用户不需要知道,但智能体需要——传进来之后它会被翻译成对应的 CLI 步骤:
|
|
474
|
-
|
|
475
|
-
```ts
|
|
476
|
-
// Blade Hub 上已安装、但当前会话还没加载:要求先 use
|
|
477
|
-
transformSlashCommand(skillId, prompt, { local: false, installed: true })
|
|
478
|
-
|
|
479
|
-
// Blade Hub 上还没安装:要求先 install 再 use
|
|
480
|
-
transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
不传第三个参数时按本地已有处理,和不带这个参数的老用法结果一致。
|
|
484
|
-
|
|
485
368
|
## 常见问题
|
|
486
369
|
|
|
487
370
|
| 现象 | 原因与解法 |
|
|
@@ -503,10 +386,9 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
503
386
|
- **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
|
|
504
387
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
505
388
|
- **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`SessionHistory`、`SessionContextStats`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
|
|
506
|
-
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
507
389
|
- **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
508
390
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
509
|
-
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`
|
|
391
|
+
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
510
392
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
511
393
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
|
512
394
|
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`
|
package/dist/index.d.ts
CHANGED
|
@@ -9,14 +9,14 @@ export { SessionHub } from "./session/hub";
|
|
|
9
9
|
export type { AgentSessionEvents, AgentSessionEventName } from "./session/events";
|
|
10
10
|
export { SessionSetupError } from "./session/definition";
|
|
11
11
|
export type { SessionConfig, SessionDefinition, SessionSetupStage, SkillDefinition, TextFile, SolutionDefinition, } from "./session/definition";
|
|
12
|
-
export { createInitialSessionState
|
|
13
|
-
export type { AskUserAnswerData, AgentLoopInfo, ActiveCompactionState, ConnectionStatus,
|
|
12
|
+
export { createInitialSessionState } from "./session/state";
|
|
13
|
+
export type { AskUserAnswerData, AgentLoopInfo, ActiveCompactionState, ConnectionStatus, SessionState, } from "./session/state";
|
|
14
14
|
export { connectEmbedded } from "./commands/embedded";
|
|
15
15
|
export type { EmbeddedChat, EmbeddedChatOptions } from "./commands/embedded";
|
|
16
16
|
export type { CommandHandler } from "./commands/registry";
|
|
17
17
|
export type { CommandEnvelope, InboundAction, InboundEnvelope } from "./commands/protocol";
|
|
18
18
|
export { isCommandEnvelope, isInboundEnvelope } from "./commands/protocol";
|
|
19
|
-
export type { AuthResource,
|
|
19
|
+
export type { AuthResource, ProvidersResponse, UserInfo } from "./resources/auth";
|
|
20
20
|
export type { HeadlessResource } from "./resources/headless";
|
|
21
21
|
export { ModelsResource } from "./resources/models";
|
|
22
22
|
export type { ModelCatalog, ModelOption } from "./resources/models";
|
|
@@ -24,11 +24,10 @@ export type { SessionsResource } from "./resources/sessions";
|
|
|
24
24
|
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
25
25
|
export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
|
|
26
26
|
export { buildMessageContent, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
|
|
27
|
-
export type { ParsedTextAttachment, ParsedTextContext
|
|
27
|
+
export type { ParsedTextAttachment, ParsedTextContext } from "./schemas/message-utils";
|
|
28
28
|
export type { ContentBlock, MemoryRef, PatchEnvelope, TurnProjection } from "./schemas/projection";
|
|
29
|
-
export { DEFAULT_REPLAY_SPEED } from "./schemas/session";
|
|
30
29
|
export { SessionInfo, SessionStatus } from "./schemas/session";
|
|
31
|
-
export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot,
|
|
30
|
+
export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, SessionDetail, SessionPortMapping, PublishedSolutionRef, TemplateId, } from "./schemas/session";
|
|
32
31
|
export { LayoutType } from "./schemas/solution";
|
|
33
32
|
export type { BizRole, Solution, SolutionAppField, SolutionAppState, SolutionAppUiConfig, } from "./schemas/solution";
|
|
34
33
|
export { Task, TaskStatus } from "./schemas/task";
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
function isAuthCallbackMessage(value) {
|
|
3
3
|
return typeof value === "object" && value !== null && value.type === "blade-agent:sdk-auth";
|
|
4
4
|
}
|
|
5
|
-
var AUTH_ERROR_HINTS = {
|
|
6
|
-
pat_unavailable: "\u6CA1\u80FD\u4E3A\u4F60\u51C6\u5907\u8BBF\u95EE\u51ED\u636E\u3002\u8BF7\u9000\u51FA\u540E\u91CD\u65B0\u767B\u5F55 Blade \u518D\u8BD5\u4E00\u6B21\uFF1B\u82E5\u4ECD\u7136\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002"
|
|
7
|
-
};
|
|
8
5
|
function randomState() {
|
|
9
6
|
const bytes = new Uint8Array(24);
|
|
10
7
|
crypto.getRandomValues(bytes);
|
|
@@ -82,22 +79,18 @@ async function loginWithPopup(client, options = {}) {
|
|
|
82
79
|
if (event.data.state !== state) return;
|
|
83
80
|
const message = event.data;
|
|
84
81
|
stopCloseWatch();
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
};
|
|
82
|
+
try {
|
|
83
|
+
popup.close();
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
91
86
|
if (message.status === "denied") {
|
|
92
|
-
closePopup();
|
|
93
87
|
settle(() => reject(new Error("\u4F60\u53D6\u6D88\u4E86\u6388\u6743\uFF0C\u672A\u5B8C\u6210\u767B\u5F55\u3002")));
|
|
94
88
|
return;
|
|
95
89
|
}
|
|
96
90
|
if (message.status !== "success" || !message.code) {
|
|
97
|
-
settle(() => reject(new Error(
|
|
91
|
+
settle(() => reject(new Error(message.error || "\u767B\u5F55\u5931\u8D25\uFF0C\u672A\u53D6\u5F97\u6388\u6743\u7801\u3002")));
|
|
98
92
|
return;
|
|
99
93
|
}
|
|
100
|
-
closePopup();
|
|
101
94
|
client.json("POST", "/api/auth/sdk/token", {
|
|
102
95
|
code: message.code,
|
|
103
96
|
state,
|
|
@@ -181,24 +174,6 @@ var AuthResource = class {
|
|
|
181
174
|
login(options) {
|
|
182
175
|
return this.client.login(options);
|
|
183
176
|
}
|
|
184
|
-
/**
|
|
185
|
-
* 用一次性 code 换 PAT。给**服务端**用:浏览器把 code 交给你自己的后端,
|
|
186
|
-
* 后端换到的 PAT 不进浏览器。浏览器里直接用 `login()` 就够了。
|
|
187
|
-
*
|
|
188
|
-
* 服务端调用时会自己补上 `Origin` 头(浏览器会自动带,服务端不会,缺了
|
|
189
|
-
* 后端报 `missing_request_origin`)。
|
|
190
|
-
*/
|
|
191
|
-
exchangeCode(params) {
|
|
192
|
-
return this.client.jsonFromInit("/api/auth/sdk/token", {
|
|
193
|
-
method: "POST",
|
|
194
|
-
headers: { Origin: params.clientOrigin },
|
|
195
|
-
body: JSON.stringify({
|
|
196
|
-
code: params.code,
|
|
197
|
-
state: params.state,
|
|
198
|
-
client_origin: params.clientOrigin
|
|
199
|
-
})
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
177
|
/** 清除 login() 存储的令牌。 */
|
|
203
178
|
logoutToken() {
|
|
204
179
|
this.client.logoutToken();
|
|
@@ -432,47 +407,6 @@ var ModelsResource = class {
|
|
|
432
407
|
}
|
|
433
408
|
};
|
|
434
409
|
|
|
435
|
-
// src/schemas/session.ts
|
|
436
|
-
import { type } from "arktype";
|
|
437
|
-
var SessionStatus = type(
|
|
438
|
-
"'created' | 'running' | 'completed' | 'failed' | 'interrupted' | 'waiting_for_input'"
|
|
439
|
-
);
|
|
440
|
-
var DEFAULT_REPLAY_SPEED = 5;
|
|
441
|
-
var SessionInfo = type({
|
|
442
|
-
id: "string",
|
|
443
|
-
intent: "string",
|
|
444
|
-
status: SessionStatus,
|
|
445
|
-
created_at: "string",
|
|
446
|
-
updated_at: "string",
|
|
447
|
-
"shared?": "boolean",
|
|
448
|
-
"memory_enabled?": "boolean",
|
|
449
|
-
"is_persistent?": "boolean",
|
|
450
|
-
"is_headless?": "boolean",
|
|
451
|
-
"viewer_role?": "'owner' | 'viewer'",
|
|
452
|
-
"template_id?": "string | null",
|
|
453
|
-
"model?": "string | null",
|
|
454
|
-
"enable_thinking?": "boolean | null",
|
|
455
|
-
"solution_id?": "string | null",
|
|
456
|
-
"solution_ref?": "unknown",
|
|
457
|
-
"biz_role_id?": "string | null",
|
|
458
|
-
"solution?": "unknown",
|
|
459
|
-
"plan_summary?": "string | null",
|
|
460
|
-
"primary_skill_id?": "string | null",
|
|
461
|
-
// ship-attack v2:后端 engine.set_bound_skill 写入的"绑定 skill id"。
|
|
462
|
-
// 未绑定 / 非 ship-attack session 为 null。
|
|
463
|
-
"bound_skill_id?": "string | null",
|
|
464
|
-
"replay_state?": "unknown",
|
|
465
|
-
"is_pinned?": "boolean",
|
|
466
|
-
"pinned_at?": "string | null",
|
|
467
|
-
"is_example?": "boolean",
|
|
468
|
-
"ports?": "unknown",
|
|
469
|
-
"disable_tools?": "string[]",
|
|
470
|
-
"runtime_type?": "string | null",
|
|
471
|
-
"daemon_id?": "string | null",
|
|
472
|
-
"workspace_path?": "string | null",
|
|
473
|
-
"match?": "unknown"
|
|
474
|
-
});
|
|
475
|
-
|
|
476
410
|
// src/session/definition.ts
|
|
477
411
|
var SessionSetupError = class extends Error {
|
|
478
412
|
constructor(message, stage, sessionId, options) {
|
|
@@ -893,28 +827,6 @@ function sourceLoopFor(loopId, loopDescriptions) {
|
|
|
893
827
|
if (!description) return null;
|
|
894
828
|
return { loop_name: loopId, description };
|
|
895
829
|
}
|
|
896
|
-
var MAX_FINAL_ARTIFACTS = 3;
|
|
897
|
-
function normalizeFinalArtifacts(raw) {
|
|
898
|
-
if (!Array.isArray(raw)) return [];
|
|
899
|
-
const artifacts = [];
|
|
900
|
-
const seen = /* @__PURE__ */ new Set();
|
|
901
|
-
for (const item of raw) {
|
|
902
|
-
if (typeof item !== "object" || item === null) continue;
|
|
903
|
-
const record = item;
|
|
904
|
-
const target = String(record.target ?? "").trim();
|
|
905
|
-
if (!target || seen.has(target)) continue;
|
|
906
|
-
const isLink = /^https?:\/\//i.test(target);
|
|
907
|
-
if (!isLink && target.split("/").includes("..")) continue;
|
|
908
|
-
seen.add(target);
|
|
909
|
-
artifacts.push({
|
|
910
|
-
kind: isLink ? "link" : "file",
|
|
911
|
-
target,
|
|
912
|
-
label: String(record.label ?? "").trim()
|
|
913
|
-
});
|
|
914
|
-
if (artifacts.length === MAX_FINAL_ARTIFACTS) break;
|
|
915
|
-
}
|
|
916
|
-
return artifacts;
|
|
917
|
-
}
|
|
918
830
|
function normalizePostChatFollowup(data, assistantEntryId) {
|
|
919
831
|
const raw = data.suggestions;
|
|
920
832
|
const suggestions = [];
|
|
@@ -926,13 +838,11 @@ function normalizePostChatFollowup(data, assistantEntryId) {
|
|
|
926
838
|
}
|
|
927
839
|
}
|
|
928
840
|
const recaption = String(data.recaption ?? "");
|
|
929
|
-
|
|
930
|
-
if (suggestions.length === 0 && !recaption && finalArtifacts.length === 0) return null;
|
|
841
|
+
if (suggestions.length === 0 && !recaption) return null;
|
|
931
842
|
return {
|
|
932
843
|
assistant_entry_id: assistantEntryId,
|
|
933
844
|
recaption,
|
|
934
|
-
suggestions: suggestions.slice(0, 3)
|
|
935
|
-
final_artifacts: finalArtifacts
|
|
845
|
+
suggestions: suggestions.slice(0, 3)
|
|
936
846
|
};
|
|
937
847
|
}
|
|
938
848
|
function normalizeChildPause(pausePayload) {
|
|
@@ -2220,16 +2130,12 @@ var SessionsResource = class {
|
|
|
2220
2130
|
pinSession(sessionId, pinned) {
|
|
2221
2131
|
return this.client.json("PATCH", `/api/sessions/${sessionId}/pin`, { pinned });
|
|
2222
2132
|
}
|
|
2223
|
-
startReplaySession(sourceSessionId, speed =
|
|
2133
|
+
startReplaySession(sourceSessionId, speed = 5) {
|
|
2224
2134
|
return this.client.json("POST", `/api/sessions/${sourceSessionId}/replay`, { speed });
|
|
2225
2135
|
}
|
|
2226
2136
|
updateReplaySession(sessionId, payload) {
|
|
2227
2137
|
return this.client.json("PATCH", `/api/sessions/${sessionId}/replay`, payload);
|
|
2228
2138
|
}
|
|
2229
|
-
/** 查询会话能否作为回放来源;不支持时 reason 可直接展示,用来提前禁用入口。 */
|
|
2230
|
-
getReplayPreview(sessionId) {
|
|
2231
|
-
return this.client.json("GET", `/api/sessions/${sessionId}/replay/preview`);
|
|
2232
|
-
}
|
|
2233
2139
|
updateSharing(sessionId, shared) {
|
|
2234
2140
|
return this.client.json("PATCH", `/api/sessions/${sessionId}/sharing`, { shared });
|
|
2235
2141
|
}
|
|
@@ -2683,15 +2589,10 @@ function contentPreview(content, maxLen = 80) {
|
|
|
2683
2589
|
const text = getTextContent(content).trim();
|
|
2684
2590
|
return text.length > maxLen ? `${text.slice(0, maxLen)}\u2026` : text;
|
|
2685
2591
|
}
|
|
2686
|
-
function transformSlashCommand(skillName, rawInput
|
|
2592
|
+
function transformSlashCommand(skillName, rawInput) {
|
|
2687
2593
|
const prompt = rawInput.replace(`<skill>${skillName}</skill>`, "").trim();
|
|
2688
|
-
|
|
2689
|
-
return prompt ? `\u8BF7\u4F7F\u7528 ${skillName} skill \u5B8C\u6210\u4EFB\u52A1
|
|
2594
|
+
return prompt ? `\u8BF7\u4F7F\u7528 ${skillName} skill \u5B8C\u6210\u4EFB\u52A1
|
|
2690
2595
|
${prompt}` : `\u8BF7\u4F7F\u7528 ${skillName} skill \u5B8C\u6210\u4EFB\u52A1`;
|
|
2691
|
-
}
|
|
2692
|
-
const steps = installed ? `\u8BF7\u5148\u8FD0\u884C blade hub skill use ${skillName} \u52A0\u8F7D\u6280\u80FD` : `\u8BE5\u6280\u80FD\u5C1A\u672A\u5B89\u88C5\u3002\u8BF7\u5148\u8FD0\u884C blade hub skill install ${skillName} \u5B89\u88C5\uFF0C\u518D\u8FD0\u884C blade hub skill use ${skillName} \u52A0\u8F7D`;
|
|
2693
|
-
return prompt ? `${steps}\uFF0C\u7136\u540E\u5B8C\u6210\u4EFB\u52A1\uFF1A
|
|
2694
|
-
${prompt}` : `${steps}\uFF0C\u7136\u540E\u4F7F\u7528\u5B83\u5B8C\u6210\u4EFB\u52A1`;
|
|
2695
2596
|
}
|
|
2696
2597
|
var ATTACHMENT_TAG_RE = /\[附件:\s*([^\]]+)\](?:[ \t]*已上传到工作区路径:[ \t]*([^\r\n]+))?/g;
|
|
2697
2598
|
var CONTEXT_PART_RE = /^\[上下文:\s*([^\]]+)\]\n([\s\S]*)$/;
|
|
@@ -2777,14 +2678,6 @@ function groupMessagesByLoop(messages) {
|
|
|
2777
2678
|
}
|
|
2778
2679
|
|
|
2779
2680
|
// src/session/state.ts
|
|
2780
|
-
function toReplaySnapshot(raw) {
|
|
2781
|
-
if (!raw || !raw.status) return null;
|
|
2782
|
-
return {
|
|
2783
|
-
isReplay: raw.status === "replay",
|
|
2784
|
-
speed: raw.speed ?? 1,
|
|
2785
|
-
sourceSessionId: raw.source_session_id ?? null
|
|
2786
|
-
};
|
|
2787
|
-
}
|
|
2788
2681
|
function createInitialSessionState(sessionId) {
|
|
2789
2682
|
return {
|
|
2790
2683
|
sessionId,
|
|
@@ -2797,9 +2690,7 @@ function createInitialSessionState(sessionId) {
|
|
|
2797
2690
|
errorMessage: null,
|
|
2798
2691
|
askAnswers: {},
|
|
2799
2692
|
agentLoops: {},
|
|
2800
|
-
activeCompaction: null
|
|
2801
|
-
replay: null,
|
|
2802
|
-
viewerRole: null
|
|
2693
|
+
activeCompaction: null
|
|
2803
2694
|
};
|
|
2804
2695
|
}
|
|
2805
2696
|
function parseAgentDescription(argumentsJson) {
|
|
@@ -3250,11 +3141,6 @@ var AgentSession = class _AgentSession {
|
|
|
3250
3141
|
patchFlushCancel = null;
|
|
3251
3142
|
joined = false;
|
|
3252
3143
|
joinPending = null;
|
|
3253
|
-
// 回放控制请求排成一条队列。连着点"5x"再点"退出回放"时,并发发出去的两个
|
|
3254
|
-
// 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用
|
|
3255
|
-
// 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个
|
|
3256
|
-
// 响应都是当时最新的,失败也只影响自己。
|
|
3257
|
-
replayQueue = Promise.resolve();
|
|
3258
3144
|
pendingReplayMessage = null;
|
|
3259
3145
|
pendingReplayMode;
|
|
3260
3146
|
recentChatEndAt = 0;
|
|
@@ -3285,10 +3171,6 @@ var AgentSession = class _AgentSession {
|
|
|
3285
3171
|
emitWithAck: async () => readonlyError(),
|
|
3286
3172
|
ensureConnected: readonlyError,
|
|
3287
3173
|
fetchTurns: async () => turns,
|
|
3288
|
-
// 静态历史没有回放身份可言,给个空详情即可,不要抛错——_bootstrap
|
|
3289
|
-
// 不会跑到这里,但保持只读语义一致。
|
|
3290
|
-
fetchSessionInfo: async () => ({ replay_state: null }),
|
|
3291
|
-
updateReplay: async () => readonlyError(),
|
|
3292
3174
|
listDir: async () => readonlyError(),
|
|
3293
3175
|
countFiles: async () => readonlyError(),
|
|
3294
3176
|
downloadFile: async () => readonlyError(),
|
|
@@ -3580,13 +3462,10 @@ var AgentSession = class _AgentSession {
|
|
|
3580
3462
|
this.joinPending = null;
|
|
3581
3463
|
try {
|
|
3582
3464
|
await this.ensureJoined();
|
|
3583
|
-
await
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
}),
|
|
3588
|
-
this.syncReplayFromSession()
|
|
3589
|
-
]);
|
|
3465
|
+
await this.syncTurnsFromHistory({
|
|
3466
|
+
clearOnEmpty: true,
|
|
3467
|
+
preserveChangesSince: turnsBeforeRejoin
|
|
3468
|
+
});
|
|
3590
3469
|
} catch {
|
|
3591
3470
|
}
|
|
3592
3471
|
}
|
|
@@ -3594,40 +3473,6 @@ var AgentSession = class _AgentSession {
|
|
|
3594
3473
|
async _bootstrap() {
|
|
3595
3474
|
await this.syncTurnsFromHistory({ suppressErrors: false });
|
|
3596
3475
|
await this.ensureJoined();
|
|
3597
|
-
await this.syncReplayFromSession();
|
|
3598
|
-
}
|
|
3599
|
-
/** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */
|
|
3600
|
-
get canControlReplay() {
|
|
3601
|
-
return this.state.viewerRole !== "viewer";
|
|
3602
|
-
}
|
|
3603
|
-
/** 拉一次会话详情,填回放状态和只读身份;失败按非回放会话处理,不挡启动。 */
|
|
3604
|
-
async syncReplayFromSession() {
|
|
3605
|
-
try {
|
|
3606
|
-
const info = await this.runtime.fetchSessionInfo(this.sessionId);
|
|
3607
|
-
const replay = toReplaySnapshot(info.replay_state);
|
|
3608
|
-
const viewerRole = info.viewer_role ?? null;
|
|
3609
|
-
this.update((s) => ({ ...s, replay, viewerRole }));
|
|
3610
|
-
} catch {
|
|
3611
|
-
}
|
|
3612
|
-
}
|
|
3613
|
-
/** 调整回放倍速;不是回放会话、或只读身份时什么都不做。 */
|
|
3614
|
-
async setReplaySpeed(speed) {
|
|
3615
|
-
if (!this.state.replay?.isReplay || !this.canControlReplay) return;
|
|
3616
|
-
await this.applyReplayControl({ speed });
|
|
3617
|
-
}
|
|
3618
|
-
/** 退出回放,之后的对话交给真实模型运行;不是回放会话、或只读身份时什么都不做。 */
|
|
3619
|
-
async exitReplay() {
|
|
3620
|
-
if (!this.state.replay?.isReplay || !this.canControlReplay) return;
|
|
3621
|
-
await this.applyReplayControl({ status: "autonomous" });
|
|
3622
|
-
}
|
|
3623
|
-
/** 把一次回放控制请求排进队列;前一个完成后才发出,响应直接安装。 */
|
|
3624
|
-
applyReplayControl(payload) {
|
|
3625
|
-
const run = this.replayQueue.then(async () => {
|
|
3626
|
-
const result = await this.runtime.updateReplay(this.sessionId, payload);
|
|
3627
|
-
this.update((s) => ({ ...s, replay: toReplaySnapshot(result) }));
|
|
3628
|
-
});
|
|
3629
|
-
this.replayQueue = run.catch(() => void 0);
|
|
3630
|
-
return run;
|
|
3631
3476
|
}
|
|
3632
3477
|
/** @internal */
|
|
3633
3478
|
_handleTurnStart(turn) {
|
|
@@ -3707,10 +3552,6 @@ var AgentSession = class _AgentSession {
|
|
|
3707
3552
|
if (data.status) {
|
|
3708
3553
|
this.update((s) => ({ ...s, status: data.status ?? s.status }));
|
|
3709
3554
|
}
|
|
3710
|
-
if (data.replay_state !== void 0) {
|
|
3711
|
-
const replay = toReplaySnapshot(data.replay_state);
|
|
3712
|
-
this.update((s) => ({ ...s, replay }));
|
|
3713
|
-
}
|
|
3714
3555
|
this.emitter.emit("sessionUpdated", {
|
|
3715
3556
|
intent: data.intent,
|
|
3716
3557
|
status: data.status,
|
|
@@ -4160,8 +4001,6 @@ var SessionHub = class {
|
|
|
4160
4001
|
}),
|
|
4161
4002
|
ensureConnected: () => this.ensureConnected(),
|
|
4162
4003
|
fetchTurns: (sessionId) => this.client.sessions.getSessionTurns(sessionId),
|
|
4163
|
-
fetchSessionInfo: (sessionId) => this.client.sessions.getSession(sessionId),
|
|
4164
|
-
updateReplay: (sessionId, payload) => this.client.sessions.updateReplaySession(sessionId, payload).then((result) => result.replay_state ?? null),
|
|
4165
4004
|
listDir: (sessionId, dirPath) => this.client.sessions.listDir(sessionId, dirPath),
|
|
4166
4005
|
countFiles: (sessionId, dirPath) => this.client.sessions.countFiles(sessionId, dirPath),
|
|
4167
4006
|
downloadFile: (sessionId, filePath, downloadName) => this.client.sessions.downloadFile(sessionId, filePath, downloadName),
|
|
@@ -4383,7 +4222,7 @@ function resolveAuthToken(options) {
|
|
|
4383
4222
|
|
|
4384
4223
|
// src/version.ts
|
|
4385
4224
|
var SDK_NAME = "agent-client";
|
|
4386
|
-
var SDK_VERSION = true ? "2608.0.5-
|
|
4225
|
+
var SDK_VERSION = true ? "2608.0.5-beta.1" : "1.1.1";
|
|
4387
4226
|
|
|
4388
4227
|
// src/socket.ts
|
|
4389
4228
|
function withSdkIdentity(auth) {
|
|
@@ -4835,6 +4674,46 @@ function connectEmbedded(options) {
|
|
|
4835
4674
|
};
|
|
4836
4675
|
}
|
|
4837
4676
|
|
|
4677
|
+
// src/schemas/session.ts
|
|
4678
|
+
import { type } from "arktype";
|
|
4679
|
+
var SessionStatus = type(
|
|
4680
|
+
"'created' | 'running' | 'completed' | 'failed' | 'interrupted' | 'waiting_for_input'"
|
|
4681
|
+
);
|
|
4682
|
+
var SessionInfo = type({
|
|
4683
|
+
id: "string",
|
|
4684
|
+
intent: "string",
|
|
4685
|
+
status: SessionStatus,
|
|
4686
|
+
created_at: "string",
|
|
4687
|
+
updated_at: "string",
|
|
4688
|
+
"shared?": "boolean",
|
|
4689
|
+
"memory_enabled?": "boolean",
|
|
4690
|
+
"is_persistent?": "boolean",
|
|
4691
|
+
"is_headless?": "boolean",
|
|
4692
|
+
"viewer_role?": "'owner' | 'viewer'",
|
|
4693
|
+
"template_id?": "string | null",
|
|
4694
|
+
"model?": "string | null",
|
|
4695
|
+
"enable_thinking?": "boolean | null",
|
|
4696
|
+
"solution_id?": "string | null",
|
|
4697
|
+
"solution_ref?": "unknown",
|
|
4698
|
+
"biz_role_id?": "string | null",
|
|
4699
|
+
"solution?": "unknown",
|
|
4700
|
+
"plan_summary?": "string | null",
|
|
4701
|
+
"primary_skill_id?": "string | null",
|
|
4702
|
+
// ship-attack v2:后端 engine.set_bound_skill 写入的"绑定 skill id"。
|
|
4703
|
+
// 未绑定 / 非 ship-attack session 为 null。
|
|
4704
|
+
"bound_skill_id?": "string | null",
|
|
4705
|
+
"replay_state?": "unknown",
|
|
4706
|
+
"is_pinned?": "boolean",
|
|
4707
|
+
"pinned_at?": "string | null",
|
|
4708
|
+
"is_example?": "boolean",
|
|
4709
|
+
"ports?": "unknown",
|
|
4710
|
+
"disable_tools?": "string[]",
|
|
4711
|
+
"runtime_type?": "string | null",
|
|
4712
|
+
"daemon_id?": "string | null",
|
|
4713
|
+
"workspace_path?": "string | null",
|
|
4714
|
+
"match?": "unknown"
|
|
4715
|
+
});
|
|
4716
|
+
|
|
4838
4717
|
// src/schemas/solution.ts
|
|
4839
4718
|
var LayoutType = /* @__PURE__ */ ((LayoutType2) => {
|
|
4840
4719
|
LayoutType2["Default"] = "default";
|
|
@@ -4866,7 +4745,6 @@ export {
|
|
|
4866
4745
|
BladeApiError,
|
|
4867
4746
|
BladeClient,
|
|
4868
4747
|
ClientProjectionBuilder,
|
|
4869
|
-
DEFAULT_REPLAY_SPEED,
|
|
4870
4748
|
LayoutType,
|
|
4871
4749
|
ModelsResource,
|
|
4872
4750
|
SDK_NAME,
|
|
@@ -4891,7 +4769,6 @@ export {
|
|
|
4891
4769
|
isHiddenInternalMessage,
|
|
4892
4770
|
isInboundEnvelope,
|
|
4893
4771
|
normalizeMessageContent,
|
|
4894
|
-
toReplaySnapshot,
|
|
4895
4772
|
transformSlashCommand
|
|
4896
4773
|
};
|
|
4897
4774
|
//# sourceMappingURL=index.js.map
|