@blade-hq/agent-client 2610.0.0-beta.30 → 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 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()` 返回取消函数;handler 抛异常只告警,不影响会话。
434
+ 完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`toolResult.source` 区分实时结果、首次连接回放和断线重连回放;`on()` 返回取消函数,handler 抛异常只告警、不影响会话。
435
435
 
436
436
  ## iframe 嵌入形态:connectEmbedded
437
437
 
@@ -583,9 +583,9 @@ 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
- - **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`ContextProjectionData`、`ContextProjectionFields`、`ContextDisplayState`、`ContextAction`、`ContextSourceInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`contextProjectionData`、`getContextDisplayState`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
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`
590
590
  - **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
591
591
  - **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`
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";
@@ -29,8 +30,8 @@ export type { SessionsResource } from "./resources/sessions";
29
30
  export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
30
31
  export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
31
32
  export { buildMessageContent, chatErrorForDisplay, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
32
- export { contextProjectionData, getContextDisplayState, } from "./schemas/context";
33
- export type { ContextAction, ContextDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
33
+ export { contextProjectionData, getContextDisplayState, getContextGroupDisplayState, groupAdjacentContextRuns, } from "./schemas/context";
34
+ export type { ContextAction, ContextDisplayState, ContextGroupDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
34
35
  export type { ParsedTextAttachment, ParsedTextContext, SkillMentionAvailability, } from "./schemas/message-utils";
35
36
  export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PostChatFollowup, TurnProjection, } from "./schemas/projection";
36
37
  export { latestPostChatFollowup } from "./schemas/projection-utils";
package/dist/index.js CHANGED
@@ -1104,12 +1104,47 @@ function contextProjectionData(fields) {
1104
1104
  };
1105
1105
  }
1106
1106
  function getContextDisplayState(context) {
1107
- const title = BUILTIN_CONTEXT_TITLES[context.context_kind] ?? nonEmptyString(context.display_title) ?? "\u5BF9\u8BDD\u80CC\u666F";
1107
+ const title = nonEmptyString(context.display_title) ?? BUILTIN_CONTEXT_TITLES[context.context_kind] ?? "\u5BF9\u8BDD\u80CC\u666F";
1108
1108
  const isRemoved = context.context_action === "removed";
1109
1109
  const summary = nonEmptyString(context.display_summary) ?? (isRemoved ? "\u5DF2\u505C\u6B62\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD" : context.context_action === "retained" ? "\u7EE7\u7EED\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD" : context.context_kind === "agent-instructions" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5BF9\u8BDD\u4F7F\u7528\u7684\u9879\u76EE\u8BF4\u660E" : context.context_kind === "skill-catalog" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u53EF\u7528\u80FD\u529B" : context.context_kind === "runtime-context" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5DE5\u4F5C\u73AF\u5883" : context.context_kind === "workspace-context" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5DE5\u4F5C\u533A\u73AF\u5883" : "\u5DF2\u66F4\u65B0\u672C\u6B21\u5BF9\u8BDD\u80CC\u666F");
1110
1110
  const detail = isRemoved ? `${title}\u5DF2\u4E0D\u518D\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD\u3002` : BUILTIN_CONTEXT_DETAILS[context.context_kind] ?? "\u8FD9\u4E9B\u4FE1\u606F\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u7406\u89E3\u5F53\u524D\u4EFB\u52A1\u3002";
1111
1111
  return { title, summary, detail, isRemoved };
1112
1112
  }
1113
+ function groupAdjacentContextRuns(kinds) {
1114
+ const runs = [];
1115
+ let current = null;
1116
+ kinds.forEach((kind, index) => {
1117
+ if (kind === null) {
1118
+ current = null;
1119
+ return;
1120
+ }
1121
+ if (current === null) {
1122
+ current = [];
1123
+ runs.push(current);
1124
+ }
1125
+ current.push(index);
1126
+ });
1127
+ return runs;
1128
+ }
1129
+ function getContextGroupDisplayState(contexts) {
1130
+ const count = contexts.length;
1131
+ if (count === 1) {
1132
+ const single = getContextDisplayState(contexts[0]);
1133
+ return { title: single.title, summary: single.summary, count };
1134
+ }
1135
+ const removed = contexts.filter(
1136
+ (context) => context.context_action === "removed"
1137
+ ).length;
1138
+ const updated = count - removed;
1139
+ const parts = [];
1140
+ if (updated > 0) parts.push(`${updated} \u9879\u5DF2\u66F4\u65B0`);
1141
+ if (removed > 0) parts.push(`${removed} \u9879\u5DF2\u505C\u7528`);
1142
+ return {
1143
+ title: "\u5BF9\u8BDD\u80CC\u666F",
1144
+ summary: parts.join(" \xB7 ") || `${count} \u9879`,
1145
+ count
1146
+ };
1147
+ }
1113
1148
 
1114
1149
  // src/shared/projection/context.ts
1115
1150
  function isRecord2(value) {
@@ -2015,7 +2050,11 @@ function projectHistory(entries) {
2015
2050
  model: stringOrNull(message.model),
2016
2051
  usage: isRecord4(message._usage) ? { ...message._usage } : null,
2017
2052
  duration_ms: numberOrZero(message._duration_ms),
2018
- started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
2053
+ started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0,
2054
+ // fork 子会话的父锚点:历史里落在消息级 _parent_fork_tool_call_id。丢掉它,
2055
+ // 刷新后工作流步骤 fork 就配不回 workflow:run 工具调用(普通 Agent fork 有
2056
+ // root Agent 工具调用兜底配对,工作流 fork 没有,子智能体卡会整体消失)。
2057
+ parent_fork_tool_call_id: stringOrNull(message._parent_fork_tool_call_id)
2019
2058
  };
2020
2059
  const isNativeToolEntry = role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.some(
2021
2060
  (toolCall) => isRecord4(toolCall) && typeof toolCall.provider === "string"
@@ -2990,10 +3029,10 @@ function isLegacyForkContextText(text) {
2990
3029
  const normalized = text.trim();
2991
3030
  return LEGACY_FORK_CONTEXT_MARKERS.every((marker) => normalized.includes(marker));
2992
3031
  }
2993
- function isHiddenInternalMessage(message) {
3032
+ function isHiddenInternalMessage(message, options = {}) {
2994
3033
  if (message.role !== "user") return false;
2995
3034
  const text = getTextContent(normalizeMessageContent(message.content));
2996
- return isSystemReminderText(text) || isSystemNotificationText(text) || isLegacyForkContextText(text);
3035
+ return isSystemReminderText(text) || isSystemNotificationText(text) || (options.includeLegacyForkContext ?? true) && isLegacyForkContextText(text);
2997
3036
  }
2998
3037
  function buildMessageContent(text, attachments) {
2999
3038
  if (attachments.length === 0) return text;
@@ -3673,6 +3712,10 @@ var AgentSession = class _AgentSession {
3673
3712
  patchFlushCancel = null;
3674
3713
  joined = false;
3675
3714
  joinPending = null;
3715
+ // bootstrap 与每次 reconnect 共用一条订阅生命周期队列。它们都会重置 join
3716
+ // 状态并临时设置 replay source,禁止并发,否则较早操作的 finally 会清掉
3717
+ // 较晚操作仍在使用的来源上下文。
3718
+ subscriptionQueue = Promise.resolve();
3676
3719
  // 回放控制请求排成一条队列。连着点"5x"再点"退出回放"时,并发发出去的两个
3677
3720
  // 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用
3678
3721
  // 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个
@@ -3682,6 +3725,7 @@ var AgentSession = class _AgentSession {
3682
3725
  pendingReplayMode;
3683
3726
  pendingReplayKbIds;
3684
3727
  recentChatEndAt = 0;
3728
+ subscriptionReplaySource = null;
3685
3729
  disposed = false;
3686
3730
  getAppContext = null;
3687
3731
  sendPending = false;
@@ -3999,27 +4043,47 @@ var AgentSession = class _AgentSession {
3999
4043
  this.update((s) => ({ ...s, connection }));
4000
4044
  }
4001
4045
  /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
4002
- async _rejoinAfterReconnect() {
4046
+ _rejoinAfterReconnect() {
4003
4047
  const turnsBeforeRejoin = this.state.turns;
4004
- this.joined = false;
4005
- this.joinPending = null;
4006
- try {
4007
- await this.ensureJoined();
4008
- await Promise.all([
4009
- this.syncTurnsFromHistory({
4010
- clearOnEmpty: true,
4011
- preserveChangesSince: turnsBeforeRejoin
4012
- }),
4013
- this.syncReplayFromSession()
4014
- ]);
4015
- } catch {
4016
- }
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
+ });
4017
4068
  }
4018
4069
  /** @internal 首次连接:加载历史 + 加入房间。 */
4019
- async _bootstrap() {
4020
- await this.syncTurnsFromHistory({ suppressErrors: false });
4021
- await this.ensureJoined();
4022
- await this.syncReplayFromSession();
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;
4023
4087
  }
4024
4088
  /** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */
4025
4089
  get canControlReplay() {
@@ -4076,7 +4140,7 @@ var AgentSession = class _AgentSession {
4076
4140
  this.applyTurn(turn);
4077
4141
  }
4078
4142
  /** @internal 历史回放通道(event_format: raw)。 */
4079
- _handleTurnEvents(events) {
4143
+ _handleTurnEvents(events, replayed = false) {
4080
4144
  if (!events.length) return;
4081
4145
  const terminalChatEndStatus = extractTerminalChatEndStatus(events);
4082
4146
  if (!terminalChatEndStatus && hasChatRunEvent2(events) && this.state.status !== "waiting_for_input") {
@@ -4088,7 +4152,10 @@ var AgentSession = class _AgentSession {
4088
4152
  const updates = this.projectionBuilder.processBatch(events);
4089
4153
  for (const update of updates) {
4090
4154
  if (update.kind === "upsert") {
4091
- this.applyTurn(update.turn);
4155
+ this.applyTurn(
4156
+ update.turn,
4157
+ replayed ? this.subscriptionReplaySource ?? "bootstrap_replay" : "live"
4158
+ );
4092
4159
  } else if (update.kind === "workspace_changed") {
4093
4160
  this.emitter.emit("workspaceChanged", {});
4094
4161
  }
@@ -4257,11 +4324,11 @@ var AgentSession = class _AgentSession {
4257
4324
  void this.syncTurnsFromHistory();
4258
4325
  this.emitter.emit("chatEnd", { status });
4259
4326
  }
4260
- applyTurn(turn) {
4327
+ applyTurn(turn, source = "live") {
4261
4328
  this.flushPatches();
4262
4329
  const previous = this.state;
4263
4330
  this.update((s) => upsertTurn(s, turn));
4264
- this.emitTurnDerivedEvents(previous, turn);
4331
+ this.emitTurnDerivedEvents(previous, turn, source);
4265
4332
  }
4266
4333
  schedulePatchFlush() {
4267
4334
  if (this.patchFlushHandle != null) return;
@@ -4307,7 +4374,7 @@ var AgentSession = class _AgentSession {
4307
4374
  }
4308
4375
  }
4309
4376
  /** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */
4310
- emitTurnDerivedEvents(previous, turn) {
4377
+ emitTurnDerivedEvents(previous, turn, source = "live") {
4311
4378
  const mode = extractModeFromBlocks(turn.blocks);
4312
4379
  if (mode && previous.mode !== mode) {
4313
4380
  this.emitter.emit("modeChange", { mode });
@@ -4356,7 +4423,7 @@ var AgentSession = class _AgentSession {
4356
4423
  const finished = toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled";
4357
4424
  if (finished && !this.finishedToolCallIds.has(toolCall.id)) {
4358
4425
  this.finishedToolCallIds.add(toolCall.id);
4359
- this.emitter.emit("toolResult", { toolCall: info, turn });
4426
+ this.emitter.emit("toolResult", { toolCall: info, turn, source });
4360
4427
  if (isOomResult(toolCall.result)) {
4361
4428
  this.notifySandboxOom(toolCall.id);
4362
4429
  }
@@ -4398,6 +4465,7 @@ var AgentSession = class _AgentSession {
4398
4465
  try {
4399
4466
  const turns = await this.runtime.fetchTurns(this.sessionId);
4400
4467
  if (turns.length === 0 && !clearOnEmpty) return;
4468
+ if (!this.joined) this.seedToolCallDeliveryBaseline(turns);
4401
4469
  this.update((state) => {
4402
4470
  const mergeBaseline = preserveChangesSince ?? turnsAtRequestStart;
4403
4471
  if (state.turns === mergeBaseline) return withTurns(state, turns);
@@ -4416,6 +4484,17 @@ var AgentSession = class _AgentSession {
4416
4484
  if (!suppressErrors) throw error;
4417
4485
  }
4418
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
+ }
4419
4498
  /**
4420
4499
  * 把历史里的指令补投给宿主页面。
4421
4500
  *
@@ -4515,16 +4594,28 @@ var SessionHub = class {
4515
4594
  * 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类"连两次
4516
4595
  * 只释放一次"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。
4517
4596
  */
4518
- async connect(sessionId) {
4597
+ async connect(sessionId, options = {}) {
4519
4598
  const existing = this.sessions.get(sessionId);
4520
4599
  if (existing && !existing.isDisposed) {
4521
4600
  this.hold(sessionId);
4601
+ try {
4602
+ options.setup?.(existing);
4603
+ } catch (error) {
4604
+ existing.dispose();
4605
+ throw error;
4606
+ }
4522
4607
  return this.bootstrapPending.get(sessionId) ?? existing;
4523
4608
  }
4524
4609
  this.ensureBound();
4525
4610
  const session = new AgentSession(sessionId, this.runtimeFor(), this.connection);
4526
4611
  this.sessions.set(sessionId, session);
4527
4612
  this.hold(sessionId);
4613
+ try {
4614
+ options.setup?.(session);
4615
+ } catch (error) {
4616
+ session.dispose();
4617
+ throw error;
4618
+ }
4528
4619
  this.ensureConnected();
4529
4620
  const bootstrap = session._bootstrap().then(() => session);
4530
4621
  this.bootstrapPending.set(sessionId, bootstrap);
@@ -4686,9 +4777,14 @@ var SessionHub = class {
4686
4777
  socket.on("turn:end", (data) => {
4687
4778
  for (const session of this.route(data.session_id)) session._handleTurnEnd(data);
4688
4779
  });
4689
- socket.on("turn:events", (data) => {
4690
- for (const session of this.route(data.session_id)) session._handleTurnEvents(data.events ?? []);
4691
- });
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
+ );
4692
4788
  socket.on("chat:start", (data) => {
4693
4789
  for (const session of this.route(data?.session_id)) session._handleChatStart();
4694
4790
  });
@@ -4818,7 +4914,7 @@ function resolveAuthToken(options) {
4818
4914
 
4819
4915
  // src/version.ts
4820
4916
  var SDK_NAME = "agent-client";
4821
- var SDK_VERSION = true ? "2610.0.0-beta.30" : "1.1.1";
4917
+ var SDK_VERSION = true ? "2610.0.0-beta.32" : "1.1.1";
4822
4918
 
4823
4919
  // src/socket.ts
4824
4920
  function withSdkIdentity(auth) {
@@ -5424,9 +5520,11 @@ export {
5424
5520
  createSocket,
5425
5521
  extractTextAttachments,
5426
5522
  getContextDisplayState,
5523
+ getContextGroupDisplayState,
5427
5524
  getFileParts,
5428
5525
  getImageParts,
5429
5526
  getTextContent,
5527
+ groupAdjacentContextRuns,
5430
5528
  groupMessagesByLoop,
5431
5529
  isCommandEnvelope,
5432
5530
  isHiddenInternalMessage,