@blade-hq/agent-client 2610.0.0-beta.31 → 2610.0.0-beta.32
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 +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +86 -29
- package/dist/index.js.map +1 -1
- package/dist/session/agent-session.d.ts +7 -1
- package/dist/session/events.d.ts +2 -0
- package/dist/session/hub.d.ts +8 -1
- package/package.json +1 -1
- package/public-api.md +9 -3
package/README.md
CHANGED
|
@@ -431,7 +431,7 @@ chat.on("chatEnd", (e) => console.log("回复结束", e.status))
|
|
|
431
431
|
chat.on("error", (e) => console.error(e.message))
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
-
完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`on()`
|
|
434
|
+
完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`toolResult.source` 区分实时结果、首次连接回放和断线重连回放;`on()` 返回取消函数,handler 抛异常只告警、不影响会话。
|
|
435
435
|
|
|
436
436
|
## iframe 嵌入形态:connectEmbedded
|
|
437
437
|
|
|
@@ -583,7 +583,7 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
583
583
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
584
584
|
- **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`GlobalSearchResult`、`GlobalSearchResultItem`、`GlobalSearchConversationResult`、`GlobalSearchFileResult`、`SessionHistory`、`SessionContextStats`、`ResultFeedback`、`ResultFeedbackReason`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
|
|
585
585
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
586
|
-
- **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
586
|
+
- **会话状态机**:`SessionHub`、`SessionConnectOptions`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
587
587
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
588
588
|
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`ContextProjectionData`、`ContextProjectionFields`、`ContextDisplayState`、`ContextGroupDisplayState`、`ContextAction`、`ContextSourceInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`contextProjectionData`、`getContextDisplayState`、`getContextGroupDisplayState`、`groupAdjacentContextRuns`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
589
589
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { SDK_NAME, SDK_VERSION } from "./version";
|
|
|
8
8
|
export { AgentSession } from "./session/agent-session";
|
|
9
9
|
export type { AttachAppOptions, SendOptions } from "./session/agent-session";
|
|
10
10
|
export { SessionHub } from "./session/hub";
|
|
11
|
+
export type { SessionConnectOptions } from "./session/hub";
|
|
11
12
|
export type { AgentSessionEvents, AgentSessionEventName } from "./session/events";
|
|
12
13
|
export { SessionSetupError } from "./session/definition";
|
|
13
14
|
export type { SessionConfig, SessionDefinition, SessionSetupStage, SkillDefinition, TextFile, SolutionDefinition, } from "./session/definition";
|
package/dist/index.js
CHANGED
|
@@ -3712,6 +3712,10 @@ var AgentSession = class _AgentSession {
|
|
|
3712
3712
|
patchFlushCancel = null;
|
|
3713
3713
|
joined = false;
|
|
3714
3714
|
joinPending = null;
|
|
3715
|
+
// bootstrap 与每次 reconnect 共用一条订阅生命周期队列。它们都会重置 join
|
|
3716
|
+
// 状态并临时设置 replay source,禁止并发,否则较早操作的 finally 会清掉
|
|
3717
|
+
// 较晚操作仍在使用的来源上下文。
|
|
3718
|
+
subscriptionQueue = Promise.resolve();
|
|
3715
3719
|
// 回放控制请求排成一条队列。连着点"5x"再点"退出回放"时,并发发出去的两个
|
|
3716
3720
|
// 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用
|
|
3717
3721
|
// 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个
|
|
@@ -3721,6 +3725,7 @@ var AgentSession = class _AgentSession {
|
|
|
3721
3725
|
pendingReplayMode;
|
|
3722
3726
|
pendingReplayKbIds;
|
|
3723
3727
|
recentChatEndAt = 0;
|
|
3728
|
+
subscriptionReplaySource = null;
|
|
3724
3729
|
disposed = false;
|
|
3725
3730
|
getAppContext = null;
|
|
3726
3731
|
sendPending = false;
|
|
@@ -4038,27 +4043,47 @@ var AgentSession = class _AgentSession {
|
|
|
4038
4043
|
this.update((s) => ({ ...s, connection }));
|
|
4039
4044
|
}
|
|
4040
4045
|
/** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
|
|
4041
|
-
|
|
4046
|
+
_rejoinAfterReconnect() {
|
|
4042
4047
|
const turnsBeforeRejoin = this.state.turns;
|
|
4043
|
-
this.
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4048
|
+
return this.enqueueSubscription(async () => {
|
|
4049
|
+
this.joined = false;
|
|
4050
|
+
this.joinPending = null;
|
|
4051
|
+
try {
|
|
4052
|
+
this.subscriptionReplaySource = "reconnect_replay";
|
|
4053
|
+
try {
|
|
4054
|
+
await this.ensureJoined();
|
|
4055
|
+
} finally {
|
|
4056
|
+
this.subscriptionReplaySource = null;
|
|
4057
|
+
}
|
|
4058
|
+
await Promise.all([
|
|
4059
|
+
this.syncTurnsFromHistory({
|
|
4060
|
+
clearOnEmpty: true,
|
|
4061
|
+
preserveChangesSince: turnsBeforeRejoin
|
|
4062
|
+
}),
|
|
4063
|
+
this.syncReplayFromSession()
|
|
4064
|
+
]);
|
|
4065
|
+
} catch {
|
|
4066
|
+
}
|
|
4067
|
+
});
|
|
4056
4068
|
}
|
|
4057
4069
|
/** @internal 首次连接:加载历史 + 加入房间。 */
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4070
|
+
_bootstrap() {
|
|
4071
|
+
return this.enqueueSubscription(async () => {
|
|
4072
|
+
await this.syncTurnsFromHistory({ suppressErrors: false });
|
|
4073
|
+
this.subscriptionReplaySource = "bootstrap_replay";
|
|
4074
|
+
try {
|
|
4075
|
+
await this.ensureJoined();
|
|
4076
|
+
} finally {
|
|
4077
|
+
this.subscriptionReplaySource = null;
|
|
4078
|
+
}
|
|
4079
|
+
await this.syncReplayFromSession();
|
|
4080
|
+
});
|
|
4081
|
+
}
|
|
4082
|
+
/** 订阅生命周期串行执行;一次失败只由自己的调用方观察,不截断后续重连。 */
|
|
4083
|
+
enqueueSubscription(operation) {
|
|
4084
|
+
const run = this.subscriptionQueue.then(operation);
|
|
4085
|
+
this.subscriptionQueue = run.catch(() => void 0);
|
|
4086
|
+
return run;
|
|
4062
4087
|
}
|
|
4063
4088
|
/** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */
|
|
4064
4089
|
get canControlReplay() {
|
|
@@ -4115,7 +4140,7 @@ var AgentSession = class _AgentSession {
|
|
|
4115
4140
|
this.applyTurn(turn);
|
|
4116
4141
|
}
|
|
4117
4142
|
/** @internal 历史回放通道(event_format: raw)。 */
|
|
4118
|
-
_handleTurnEvents(events) {
|
|
4143
|
+
_handleTurnEvents(events, replayed = false) {
|
|
4119
4144
|
if (!events.length) return;
|
|
4120
4145
|
const terminalChatEndStatus = extractTerminalChatEndStatus(events);
|
|
4121
4146
|
if (!terminalChatEndStatus && hasChatRunEvent2(events) && this.state.status !== "waiting_for_input") {
|
|
@@ -4127,7 +4152,10 @@ var AgentSession = class _AgentSession {
|
|
|
4127
4152
|
const updates = this.projectionBuilder.processBatch(events);
|
|
4128
4153
|
for (const update of updates) {
|
|
4129
4154
|
if (update.kind === "upsert") {
|
|
4130
|
-
this.applyTurn(
|
|
4155
|
+
this.applyTurn(
|
|
4156
|
+
update.turn,
|
|
4157
|
+
replayed ? this.subscriptionReplaySource ?? "bootstrap_replay" : "live"
|
|
4158
|
+
);
|
|
4131
4159
|
} else if (update.kind === "workspace_changed") {
|
|
4132
4160
|
this.emitter.emit("workspaceChanged", {});
|
|
4133
4161
|
}
|
|
@@ -4296,11 +4324,11 @@ var AgentSession = class _AgentSession {
|
|
|
4296
4324
|
void this.syncTurnsFromHistory();
|
|
4297
4325
|
this.emitter.emit("chatEnd", { status });
|
|
4298
4326
|
}
|
|
4299
|
-
applyTurn(turn) {
|
|
4327
|
+
applyTurn(turn, source = "live") {
|
|
4300
4328
|
this.flushPatches();
|
|
4301
4329
|
const previous = this.state;
|
|
4302
4330
|
this.update((s) => upsertTurn(s, turn));
|
|
4303
|
-
this.emitTurnDerivedEvents(previous, turn);
|
|
4331
|
+
this.emitTurnDerivedEvents(previous, turn, source);
|
|
4304
4332
|
}
|
|
4305
4333
|
schedulePatchFlush() {
|
|
4306
4334
|
if (this.patchFlushHandle != null) return;
|
|
@@ -4346,7 +4374,7 @@ var AgentSession = class _AgentSession {
|
|
|
4346
4374
|
}
|
|
4347
4375
|
}
|
|
4348
4376
|
/** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */
|
|
4349
|
-
emitTurnDerivedEvents(previous, turn) {
|
|
4377
|
+
emitTurnDerivedEvents(previous, turn, source = "live") {
|
|
4350
4378
|
const mode = extractModeFromBlocks(turn.blocks);
|
|
4351
4379
|
if (mode && previous.mode !== mode) {
|
|
4352
4380
|
this.emitter.emit("modeChange", { mode });
|
|
@@ -4395,7 +4423,7 @@ var AgentSession = class _AgentSession {
|
|
|
4395
4423
|
const finished = toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled";
|
|
4396
4424
|
if (finished && !this.finishedToolCallIds.has(toolCall.id)) {
|
|
4397
4425
|
this.finishedToolCallIds.add(toolCall.id);
|
|
4398
|
-
this.emitter.emit("toolResult", { toolCall: info, turn });
|
|
4426
|
+
this.emitter.emit("toolResult", { toolCall: info, turn, source });
|
|
4399
4427
|
if (isOomResult(toolCall.result)) {
|
|
4400
4428
|
this.notifySandboxOom(toolCall.id);
|
|
4401
4429
|
}
|
|
@@ -4437,6 +4465,7 @@ var AgentSession = class _AgentSession {
|
|
|
4437
4465
|
try {
|
|
4438
4466
|
const turns = await this.runtime.fetchTurns(this.sessionId);
|
|
4439
4467
|
if (turns.length === 0 && !clearOnEmpty) return;
|
|
4468
|
+
if (!this.joined) this.seedToolCallDeliveryBaseline(turns);
|
|
4440
4469
|
this.update((state) => {
|
|
4441
4470
|
const mergeBaseline = preserveChangesSince ?? turnsAtRequestStart;
|
|
4442
4471
|
if (state.turns === mergeBaseline) return withTurns(state, turns);
|
|
@@ -4455,6 +4484,17 @@ var AgentSession = class _AgentSession {
|
|
|
4455
4484
|
if (!suppressErrors) throw error;
|
|
4456
4485
|
}
|
|
4457
4486
|
}
|
|
4487
|
+
/** 首次订阅前的 REST 历史建立语义事件基线,随后同一工具的订阅回放不再投递。 */
|
|
4488
|
+
seedToolCallDeliveryBaseline(turns) {
|
|
4489
|
+
for (const turn of turns) {
|
|
4490
|
+
for (const toolCall of turn.tool_calls) {
|
|
4491
|
+
this.seenToolCallIds.add(toolCall.id);
|
|
4492
|
+
if (toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled") {
|
|
4493
|
+
this.finishedToolCallIds.add(toolCall.id);
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4458
4498
|
/**
|
|
4459
4499
|
* 把历史里的指令补投给宿主页面。
|
|
4460
4500
|
*
|
|
@@ -4554,16 +4594,28 @@ var SessionHub = class {
|
|
|
4554
4594
|
* 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类"连两次
|
|
4555
4595
|
* 只释放一次"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。
|
|
4556
4596
|
*/
|
|
4557
|
-
async connect(sessionId) {
|
|
4597
|
+
async connect(sessionId, options = {}) {
|
|
4558
4598
|
const existing = this.sessions.get(sessionId);
|
|
4559
4599
|
if (existing && !existing.isDisposed) {
|
|
4560
4600
|
this.hold(sessionId);
|
|
4601
|
+
try {
|
|
4602
|
+
options.setup?.(existing);
|
|
4603
|
+
} catch (error) {
|
|
4604
|
+
existing.dispose();
|
|
4605
|
+
throw error;
|
|
4606
|
+
}
|
|
4561
4607
|
return this.bootstrapPending.get(sessionId) ?? existing;
|
|
4562
4608
|
}
|
|
4563
4609
|
this.ensureBound();
|
|
4564
4610
|
const session = new AgentSession(sessionId, this.runtimeFor(), this.connection);
|
|
4565
4611
|
this.sessions.set(sessionId, session);
|
|
4566
4612
|
this.hold(sessionId);
|
|
4613
|
+
try {
|
|
4614
|
+
options.setup?.(session);
|
|
4615
|
+
} catch (error) {
|
|
4616
|
+
session.dispose();
|
|
4617
|
+
throw error;
|
|
4618
|
+
}
|
|
4567
4619
|
this.ensureConnected();
|
|
4568
4620
|
const bootstrap = session._bootstrap().then(() => session);
|
|
4569
4621
|
this.bootstrapPending.set(sessionId, bootstrap);
|
|
@@ -4725,9 +4777,14 @@ var SessionHub = class {
|
|
|
4725
4777
|
socket.on("turn:end", (data) => {
|
|
4726
4778
|
for (const session of this.route(data.session_id)) session._handleTurnEnd(data);
|
|
4727
4779
|
});
|
|
4728
|
-
socket.on(
|
|
4729
|
-
|
|
4730
|
-
|
|
4780
|
+
socket.on(
|
|
4781
|
+
"turn:events",
|
|
4782
|
+
(data) => {
|
|
4783
|
+
for (const session of this.route(data.session_id)) {
|
|
4784
|
+
session._handleTurnEvents(data.events ?? [], data.replayed === true);
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
);
|
|
4731
4788
|
socket.on("chat:start", (data) => {
|
|
4732
4789
|
for (const session of this.route(data?.session_id)) session._handleChatStart();
|
|
4733
4790
|
});
|
|
@@ -4857,7 +4914,7 @@ function resolveAuthToken(options) {
|
|
|
4857
4914
|
|
|
4858
4915
|
// src/version.ts
|
|
4859
4916
|
var SDK_NAME = "agent-client";
|
|
4860
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4917
|
+
var SDK_VERSION = true ? "2610.0.0-beta.32" : "1.1.1";
|
|
4861
4918
|
|
|
4862
4919
|
// src/socket.ts
|
|
4863
4920
|
function withSdkIdentity(auth) {
|