@blade-hq/agent-client 2610.0.0-beta.6 → 2610.0.0-beta.8

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
@@ -523,4 +523,4 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
523
523
  - **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
524
524
  - **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
525
525
  - **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
526
- - **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`
526
+ - **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ 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, toReplaySnapshot } from "./session/state";
12
+ export { createInitialSessionState, reconcileOptimisticUserTurns, toReplaySnapshot, } from "./session/state";
13
13
  export type { AskUserAnswerData, AgentLoopInfo, ActiveCompactionState, ConnectionStatus, ReplaySnapshot, SessionState, } from "./session/state";
14
14
  export { connectEmbedded } from "./commands/embedded";
15
15
  export type { EmbeddedChat, EmbeddedChatOptions } from "./commands/embedded";
package/dist/index.js CHANGED
@@ -3140,6 +3140,25 @@ function orderTurns(turns) {
3140
3140
  }
3141
3141
  return turns;
3142
3142
  }
3143
+ function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
3144
+ const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]));
3145
+ const optimisticUserTurn = currentTurns.find(
3146
+ (turn) => turn.role === "user" && turn.turn_id.startsWith("local-user-")
3147
+ );
3148
+ let optimisticUserMatched = false;
3149
+ return incomingTurns.map((turn) => {
3150
+ const current = currentById.get(turn.turn_id);
3151
+ if (current) {
3152
+ const currentRenderId = current.client_render_id;
3153
+ return turn.client_render_id || !currentRenderId ? turn : { ...turn, client_render_id: currentRenderId };
3154
+ }
3155
+ if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && !turn.turn_id.startsWith("local-user-")) {
3156
+ optimisticUserMatched = true;
3157
+ return { ...turn, client_render_id: optimisticUserTurn.turn_id };
3158
+ }
3159
+ return turn;
3160
+ });
3161
+ }
3143
3162
  function areAgentLoopsEqual(left, right) {
3144
3163
  if (!left) return Object.keys(right).length === 0;
3145
3164
  const leftEntries = Object.entries(left);
@@ -3151,7 +3170,7 @@ function areAgentLoopsEqual(left, right) {
3151
3170
  });
3152
3171
  }
3153
3172
  function withTurns(state, turns) {
3154
- const orderedTurns = orderTurns(turns);
3173
+ const orderedTurns = orderTurns(reconcileOptimisticUserTurns(state.turns, turns));
3155
3174
  const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
3156
3175
  const isWaitingForInput = orderedTurns.some(
3157
3176
  (turn) => turn.tool_calls.some((toolCall) => toolCall.status === "awaiting_answer")
@@ -3161,7 +3180,13 @@ function withTurns(state, turns) {
3161
3180
  const preservedErrors = lastTurnId ? state.messages.filter(
3162
3181
  (m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
3163
3182
  ) : [];
3164
- const mergedMessages = preservedErrors.length > 0 ? [...messages, ...preservedErrors] : messages;
3183
+ const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]));
3184
+ const messagesWithRenderIds = messages.map((message) => {
3185
+ if (!message.entry_id) return message;
3186
+ const renderId = turnById.get(message.entry_id)?.client_render_id;
3187
+ return renderId ? { ...message, render_id: renderId } : message;
3188
+ });
3189
+ const mergedMessages = preservedErrors.length > 0 ? [...messagesWithRenderIds, ...preservedErrors] : messagesWithRenderIds;
3165
3190
  const latestMode = [...orderedTurns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
3166
3191
  return {
3167
3192
  ...state,
@@ -3196,14 +3221,17 @@ function addUserMessage(state, content) {
3196
3221
  }
3197
3222
  function upsertTurn(state, turn) {
3198
3223
  let existing = [...state.turns];
3199
- if (turn.role === "user" && !turn.turn_id.startsWith("local-user-")) {
3200
- existing = existing.filter((t) => !t.turn_id.startsWith("local-user-"));
3224
+ const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn]);
3225
+ if (nextTurn.client_render_id && turn.role === "user") {
3226
+ existing = existing.filter(
3227
+ (item) => !(item.role === "user" && item.turn_id.startsWith("local-user-"))
3228
+ );
3201
3229
  }
3202
- const index = existing.findIndex((item) => item.turn_id === turn.turn_id);
3230
+ const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id);
3203
3231
  if (index >= 0) {
3204
- existing[index] = turn;
3232
+ existing[index] = nextTurn;
3205
3233
  } else {
3206
- existing.push(turn);
3234
+ existing.push(nextTurn);
3207
3235
  }
3208
3236
  return withTurns(state, existing);
3209
3237
  }
@@ -4471,7 +4499,7 @@ function resolveAuthToken(options) {
4471
4499
 
4472
4500
  // src/version.ts
4473
4501
  var SDK_NAME = "agent-client";
4474
- var SDK_VERSION = true ? "2610.0.0-beta.6" : "1.1.1";
4502
+ var SDK_VERSION = true ? "2610.0.0-beta.8" : "1.1.1";
4475
4503
 
4476
4504
  // src/socket.ts
4477
4505
  function withSdkIdentity(auth) {
@@ -4994,6 +5022,7 @@ export {
4994
5022
  isInboundEnvelope,
4995
5023
  latestPostChatFollowup,
4996
5024
  normalizeMessageContent,
5025
+ reconcileOptimisticUserTurns,
4997
5026
  toReplaySnapshot,
4998
5027
  transformSlashCommand
4999
5028
  };