@blade-hq/agent-client 1.2.1-alpha.2 → 1.2.1-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 CHANGED
@@ -182,7 +182,7 @@ const unsubscribe = chat.subscribe(() => rerender(chat.getState()))
182
182
  ### 动作
183
183
 
184
184
  ```ts
185
- await chat.send("你好") // 发消息(字符串或多模态内容)
185
+ const accepted = await chat.send("你好") // 服务端接受后为 true;拒绝时为 false
186
186
  await chat.send("换个方案", { mode: "planning" }) // 指定模式/模型等选项
187
187
  chat.append("补充:预算不超过 5 万") // 智能体运行中追加说明
188
188
  await chat.stop() // 停止当前回复
@@ -385,10 +385,10 @@ function Message({ message }: { message: ChatMessage }) {
385
385
  - **SDK 身份**:`SDK_NAME`、`SDK_VERSION`
386
386
  - **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
387
387
  - **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
388
- - **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`SessionHistory`、`SessionContextStats`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
388
+ - **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`SessionHistory`、`SessionContextStats`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
389
389
  - **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
390
390
  - **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
391
391
  - **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
392
- - **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`
392
+ - **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
393
393
  - **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
394
394
  - **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`
package/dist/index.d.ts CHANGED
@@ -21,17 +21,17 @@ export type { HeadlessResource } from "./resources/headless";
21
21
  export { ModelsResource } from "./resources/models";
22
22
  export type { ModelCatalog, ModelOption } from "./resources/models";
23
23
  export type { SessionsResource } from "./resources/sessions";
24
- export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, PaginatedSessionsResult, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
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
27
  export type { ParsedTextAttachment, ParsedTextContext } from "./schemas/message-utils";
28
28
  export type { ContentBlock, MemoryRef, PatchEnvelope, TurnProjection } from "./schemas/projection";
29
29
  export { SessionInfo, SessionStatus } from "./schemas/session";
30
- export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, SessionDetail, SessionPortMapping, TemplateId, } from "./schemas/session";
30
+ export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, SessionDetail, SessionPortMapping, PublishedSolutionRef, TemplateId, } from "./schemas/session";
31
31
  export { LayoutType } from "./schemas/solution";
32
32
  export type { BizRole, Solution, SolutionAppField, SolutionAppState, SolutionAppUiConfig, } from "./schemas/solution";
33
33
  export { Task, TaskStatus } from "./schemas/task";
34
- export type { BackgroundTask } from "./schemas/background";
34
+ export type { BackgroundTask, BackgroundTaskStopResult } from "./schemas/background";
35
35
  export { ClientProjectionBuilder } from "./shared/projection";
36
36
  export type { RawEvent } from "./shared/projection";
37
37
  export { createSocket } from "./socket";
package/dist/index.js CHANGED
@@ -319,13 +319,22 @@ var HeadlessResource = class {
319
319
  socket.on("chat:end", onChatEnd);
320
320
  socket.on("system:error", onSystemError);
321
321
  socket.emit("session:subscribe", { session_id, event_format: "raw" });
322
- socket.emit("chat:send", {
323
- session_id,
324
- message: prompt,
325
- headless: true,
326
- output_schema: options.schema ?? null,
327
- model: options.model ?? null
328
- });
322
+ socket.emit(
323
+ "chat:send",
324
+ {
325
+ session_id,
326
+ message: prompt,
327
+ headless: true,
328
+ output_schema: options.schema ?? null,
329
+ model: options.model ?? null
330
+ },
331
+ (response) => {
332
+ if (response.status === "accepted") return;
333
+ rejectAfterChatEnd(
334
+ new HeadlessError(response.message ?? "headless run was not accepted", response)
335
+ );
336
+ }
337
+ );
329
338
  });
330
339
  }
331
340
  };
@@ -1841,10 +1850,12 @@ function findLatestAssistant(turns, loopId) {
1841
1850
 
1842
1851
  // src/resources/sessions.ts
1843
1852
  function toCreateSessionPayload(request) {
1853
+ const solutionRef = request.solution_ref ?? externalSolutionRef(request.solution_id);
1844
1854
  return {
1845
1855
  intent: request.intent ?? "",
1846
1856
  template_id: request.template_id,
1847
- solution_id: request.solution_id,
1857
+ solution_id: solutionRef ? void 0 : request.solution_id,
1858
+ solution_ref: solutionRef,
1848
1859
  biz_role_id: request.biz_role_id ?? null,
1849
1860
  model: request.model ?? null,
1850
1861
  enable_thinking: request.enable_thinking ?? null,
@@ -1853,11 +1864,33 @@ function toCreateSessionPayload(request) {
1853
1864
  env: request.env,
1854
1865
  disable_tools: request.disable_tools ?? null,
1855
1866
  session_solution_asset_id: request.session_solution_asset_id ?? null,
1867
+ solution_snapshot_session_id: request.solution_snapshot_session_id ?? null,
1856
1868
  compaction_ratio: request.compaction_ratio ?? null,
1857
1869
  ...request.runtime_type ? { runtime_type: request.runtime_type } : {},
1858
1870
  ...request.daemon_id ? { daemon_id: request.daemon_id } : {}
1859
1871
  };
1860
1872
  }
1873
+ var builtinSolutionIds = /* @__PURE__ */ new Set([
1874
+ "app-dev",
1875
+ "general_chat",
1876
+ "multica",
1877
+ "night_build",
1878
+ "skill_editor",
1879
+ "smart_bid",
1880
+ "solution_generate"
1881
+ ]);
1882
+ function externalSolutionRef(solutionId) {
1883
+ if (!solutionId) return void 0;
1884
+ const normalized = solutionId === "default" ? "general_chat" : solutionId.trim();
1885
+ if (builtinSolutionIds.has(normalized)) {
1886
+ return { source: "builtin", name: normalized };
1887
+ }
1888
+ const parts = normalized.split("/");
1889
+ if (parts.length === 2 && parts.every(Boolean)) {
1890
+ return { source: "hub", org: parts[0], name: parts[1] };
1891
+ }
1892
+ return void 0;
1893
+ }
1861
1894
  var SessionsResource = class {
1862
1895
  constructor(client) {
1863
1896
  this.client = client;
@@ -1965,13 +1998,18 @@ var SessionsResource = class {
1965
1998
  offset,
1966
1999
  template_id_prefix,
1967
2000
  solution_id,
2001
+ solution_registry_id,
1968
2002
  q
1969
2003
  }) {
1970
2004
  const searchParams = new URLSearchParams();
1971
2005
  searchParams.set("limit", String(limit));
1972
2006
  searchParams.set("offset", String(offset));
1973
2007
  if (template_id_prefix) searchParams.set("template_id_prefix", template_id_prefix);
1974
- if (solution_id) searchParams.set("solution_id", solution_id);
2008
+ if (solution_registry_id) {
2009
+ searchParams.set("solution_registry_id", solution_registry_id);
2010
+ } else if (solution_id) {
2011
+ searchParams.set("solution_id", solution_id);
2012
+ }
1975
2013
  const trimmedQuery = q?.trim();
1976
2014
  if (trimmedQuery) searchParams.set("q", trimmedQuery);
1977
2015
  return this.client.json("GET", `/api/sessions?${searchParams.toString()}`);
@@ -2227,11 +2265,23 @@ var SessionsResource = class {
2227
2265
  const res = await this.client.formData("POST", "/api/sessions/preview-import", form);
2228
2266
  return res.json();
2229
2267
  }
2230
- async importSession(file, name, solutionId) {
2268
+ async importSession(file, name, solutionOverride) {
2231
2269
  const form = new FormData();
2232
2270
  form.append("file", file);
2233
2271
  if (name) form.append("name", name);
2234
- if (solutionId) form.append("solution_id", solutionId);
2272
+ if (typeof solutionOverride === "string") {
2273
+ if (solutionOverride) form.append("solution_id", solutionOverride);
2274
+ } else if (solutionOverride) {
2275
+ if (solutionOverride.solution_ref) {
2276
+ form.append("solution_ref", JSON.stringify(solutionOverride.solution_ref));
2277
+ }
2278
+ if (solutionOverride.solution_snapshot_session_id) {
2279
+ form.append(
2280
+ "solution_snapshot_session_id",
2281
+ solutionOverride.solution_snapshot_session_id
2282
+ );
2283
+ }
2284
+ }
2235
2285
  const res = await this.client.formData("POST", "/api/sessions/import", form);
2236
2286
  return res.json();
2237
2287
  }
@@ -2996,6 +3046,11 @@ function extractTerminalChatEndStatus(events) {
2996
3046
  }
2997
3047
  return null;
2998
3048
  }
3049
+ function hasChatRunEvent(events) {
3050
+ return events.some(
3051
+ (event) => event.type !== "session:post_chat_followup" && !event.type.startsWith("compaction:")
3052
+ );
3053
+ }
2999
3054
  function isUiMetaLike(value) {
3000
3055
  return isRecord5(value) && ("resourceHTML" in value || "resourceUri" in value || "resourceURI" in value);
3001
3056
  }
@@ -3018,6 +3073,7 @@ var AgentSession = class _AgentSession {
3018
3073
  disposed = false;
3019
3074
  getAppContext = null;
3020
3075
  sendPending = false;
3076
+ manualCompactionPending = false;
3021
3077
  deliveredCommandKeys = /* @__PURE__ */ new Set();
3022
3078
  deliveredToolPreviews = /* @__PURE__ */ new Map();
3023
3079
  oomNotifiedKeys = /* @__PURE__ */ new Set();
@@ -3112,22 +3168,26 @@ var AgentSession = class _AgentSession {
3112
3168
  /** 发送一条消息。字符串或多模态内容均可。 */
3113
3169
  async send(content, options = {}) {
3114
3170
  this.runtime.ensureConnected();
3115
- if (this.state.isStreaming || this.sendPending) {
3116
- this.update((s) => addErrorMessage(s, "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001\u3002"));
3117
- return;
3171
+ if (this.state.isStreaming || this.state.activeCompaction || this.sendPending || this.manualCompactionPending) {
3172
+ this.update(
3173
+ (s) => addErrorMessage(s, "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\u6216\u5BF9\u8BDD\u6B63\u5728\u6574\u7406\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001\u3002")
3174
+ );
3175
+ return false;
3118
3176
  }
3119
3177
  this.sendPending = true;
3120
3178
  try {
3121
- await this.sendUnlocked(content, options);
3179
+ return await this.sendUnlocked(content, options);
3122
3180
  } finally {
3123
3181
  this.sendPending = false;
3124
3182
  }
3125
3183
  }
3126
3184
  async sendUnlocked(content, options) {
3127
3185
  await this.ensureIdleBeforeSend();
3128
- if (this.state.isStreaming) {
3129
- this.update((s) => addErrorMessage(s, "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001\u3002"));
3130
- return;
3186
+ if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {
3187
+ this.update(
3188
+ (s) => addErrorMessage(s, "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\u6216\u5BF9\u8BDD\u6B63\u5728\u6574\u7406\uFF0C\u8BF7\u7A0D\u540E\u518D\u53D1\u9001\u3002")
3189
+ );
3190
+ return false;
3131
3191
  }
3132
3192
  let appContext;
3133
3193
  if (this.getAppContext) {
@@ -3148,19 +3208,28 @@ var AgentSession = class _AgentSession {
3148
3208
  } catch (error) {
3149
3209
  const message = error instanceof Error && error.message ? `\u8BFB\u53D6\u5E94\u7528\u4E0A\u4E0B\u6587\u5931\u8D25\uFF1A${error.message}` : "\u8BFB\u53D6\u5E94\u7528\u4E0A\u4E0B\u6587\u5931\u8D25\uFF0C\u6D88\u606F\u672A\u53D1\u9001";
3150
3210
  this.update((s) => addErrorMessage(s, message));
3151
- return;
3211
+ return false;
3152
3212
  }
3153
3213
  }
3154
3214
  const askUserAnswer = options.askUserAnswer;
3215
+ let optimisticTurnId = null;
3216
+ let optimisticAskAnswer;
3217
+ let previousAskAnswer;
3155
3218
  if (!(askUserAnswer && typeof askUserAnswer.tool_call_id === "string")) {
3156
- this.update((s) => addUserMessage(s, content));
3219
+ this.update((state) => {
3220
+ const next = addUserMessage(state, content);
3221
+ optimisticTurnId = next.turns.at(-1)?.turn_id ?? null;
3222
+ return next;
3223
+ });
3157
3224
  }
3158
3225
  this.update((s) => ({ ...s, isStreaming: true }));
3159
3226
  if (askUserAnswer && typeof askUserAnswer.tool_call_id === "string") {
3160
3227
  const { tool_call_id, ...rest } = askUserAnswer;
3228
+ previousAskAnswer = this.state.askAnswers[tool_call_id];
3229
+ optimisticAskAnswer = rest;
3161
3230
  this.update((s) => ({
3162
3231
  ...s,
3163
- askAnswers: { ...s.askAnswers, [tool_call_id]: rest }
3232
+ askAnswers: { ...s.askAnswers, [tool_call_id]: optimisticAskAnswer }
3164
3233
  }));
3165
3234
  }
3166
3235
  if (!options.replayDecision) {
@@ -3181,15 +3250,54 @@ var AgentSession = class _AgentSession {
3181
3250
  try {
3182
3251
  await this.ensureJoined();
3183
3252
  } catch (error) {
3184
- this.update(
3185
- (s) => addErrorMessage(
3186
- { ...s, isStreaming: false, status: "failed" },
3187
- error instanceof Error && error.message ? error.message : "\u4F1A\u8BDD\u8BA2\u9605\u5931\u8D25\uFF0C\u6D88\u606F\u672A\u53D1\u9001"
3188
- )
3253
+ this.rollbackOptimisticSend(
3254
+ optimisticTurnId,
3255
+ askUserAnswer,
3256
+ optimisticAskAnswer,
3257
+ previousAskAnswer,
3258
+ error instanceof Error && error.message ? error.message : "\u4F1A\u8BDD\u8BA2\u9605\u5931\u8D25\uFF0C\u6D88\u606F\u672A\u53D1\u9001"
3189
3259
  );
3190
- return;
3260
+ return false;
3261
+ }
3262
+ try {
3263
+ const response = await this.runtime.emitWithAck("chat:send", payload, 3e4);
3264
+ if (response?.status !== "accepted") {
3265
+ throw new Error(
3266
+ typeof response?.message === "string" ? response.message : "\u6D88\u606F\u672A\u88AB\u670D\u52A1\u7AEF\u63A5\u53D7"
3267
+ );
3268
+ }
3269
+ return true;
3270
+ } catch (error) {
3271
+ this.rollbackOptimisticSend(
3272
+ optimisticTurnId,
3273
+ askUserAnswer,
3274
+ optimisticAskAnswer,
3275
+ previousAskAnswer,
3276
+ error instanceof Error && error.message ? error.message : "\u6D88\u606F\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"
3277
+ );
3278
+ return false;
3191
3279
  }
3192
- this.runtime.emitEvent("chat:send", payload);
3280
+ }
3281
+ rollbackOptimisticSend(optimisticTurnId, askUserAnswer, optimisticAskAnswer, previousAskAnswer, message) {
3282
+ this.pendingReplayMessage = null;
3283
+ this.pendingReplayMode = void 0;
3284
+ this.update((current) => {
3285
+ let next = optimisticTurnId ? withTurns(
3286
+ current,
3287
+ current.turns.filter((turn) => turn.turn_id !== optimisticTurnId)
3288
+ ) : current;
3289
+ const toolCallId = askUserAnswer && typeof askUserAnswer.tool_call_id === "string" ? askUserAnswer.tool_call_id : null;
3290
+ if (toolCallId && next.askAnswers[toolCallId] === optimisticAskAnswer) {
3291
+ const askAnswers = { ...next.askAnswers };
3292
+ if (previousAskAnswer === void 0) {
3293
+ delete askAnswers[toolCallId];
3294
+ } else {
3295
+ askAnswers[toolCallId] = previousAskAnswer;
3296
+ }
3297
+ next = { ...next, askAnswers };
3298
+ }
3299
+ return addErrorMessage({ ...next, isStreaming: false }, message);
3300
+ });
3193
3301
  }
3194
3302
  /** 智能体运行期间追加补充说明(不打断当前回复)。 */
3195
3303
  append(text) {
@@ -3203,7 +3311,28 @@ var AgentSession = class _AgentSession {
3203
3311
  }
3204
3312
  /** 手动触发上下文压缩。 */
3205
3313
  compact() {
3206
- return this.runtime.emitWithAck("chat:compact", { session_id: this.sessionId }, 3e4).then((response) => response ?? {});
3314
+ if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {
3315
+ return Promise.resolve({
3316
+ status: "error",
3317
+ message: "\u5F53\u524D\u56DE\u590D\u5C1A\u672A\u7ED3\u675F\u6216\u5BF9\u8BDD\u6B63\u5728\u6574\u7406\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002"
3318
+ });
3319
+ }
3320
+ this.manualCompactionPending = true;
3321
+ this.update((state) => ({
3322
+ ...state,
3323
+ activeCompaction: {
3324
+ turn_id: "pending-manual-compaction",
3325
+ compaction_id: "pending-manual-compaction",
3326
+ status: "streaming",
3327
+ trigger: "manual"
3328
+ }
3329
+ }));
3330
+ return this.runtime.emitWithAck("chat:compact", { session_id: this.sessionId }, 3e4).then((response) => response ?? {}).finally(() => {
3331
+ this.manualCompactionPending = false;
3332
+ if (this.state.activeCompaction?.compaction_id === "pending-manual-compaction") {
3333
+ this.update((state) => ({ ...state, activeCompaction: null }));
3334
+ }
3335
+ });
3207
3336
  }
3208
3337
  /**
3209
3338
  * 把一段业务数据作为附件放进聊天输入框(比如地图上选中的点位)。
@@ -3293,10 +3422,7 @@ var AgentSession = class _AgentSession {
3293
3422
  _handleTurnEvents(events) {
3294
3423
  if (!events.length) return;
3295
3424
  const terminalChatEndStatus = extractTerminalChatEndStatus(events);
3296
- const followupOnly = events.every(
3297
- (event) => event.type === "session:post_chat_followup"
3298
- );
3299
- if (!terminalChatEndStatus && !followupOnly) {
3425
+ if (!terminalChatEndStatus && hasChatRunEvent(events)) {
3300
3426
  this.markRunningIfIdle();
3301
3427
  }
3302
3428
  if (this.state.turns.length) {
@@ -3370,11 +3496,30 @@ var AgentSession = class _AgentSession {
3370
3496
  this.pendingReplayMessage = null;
3371
3497
  this.pendingReplayMode = void 0;
3372
3498
  const respond = (decision) => {
3373
- this.runtime.emitEvent("chat:send", {
3374
- session_id: this.sessionId,
3375
- message,
3376
- mode,
3377
- replay_decision: decision
3499
+ void this.runtime.emitWithAck(
3500
+ "chat:send",
3501
+ {
3502
+ session_id: this.sessionId,
3503
+ message,
3504
+ mode,
3505
+ replay_decision: decision
3506
+ },
3507
+ 3e4
3508
+ ).then((response) => {
3509
+ if (response?.status === "accepted") return;
3510
+ this.update(
3511
+ (state) => addErrorMessage(
3512
+ { ...state, isStreaming: false },
3513
+ typeof response?.message === "string" ? response.message : "\u6D88\u606F\u672A\u88AB\u670D\u52A1\u7AEF\u63A5\u53D7"
3514
+ )
3515
+ );
3516
+ }).catch((error) => {
3517
+ this.update(
3518
+ (state) => addErrorMessage(
3519
+ { ...state, isStreaming: false },
3520
+ error instanceof Error && error.message ? error.message : "\u6D88\u606F\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"
3521
+ )
3522
+ );
3378
3523
  });
3379
3524
  };
3380
3525
  const handled = this.emitter.emitFirst("replayMismatch", {
@@ -3656,6 +3801,18 @@ var AgentSession = class _AgentSession {
3656
3801
  };
3657
3802
 
3658
3803
  // src/session/hub.ts
3804
+ var BACKGROUND_STATUSES = [
3805
+ "starting",
3806
+ "running",
3807
+ "cancelling",
3808
+ "succeeded",
3809
+ "failed",
3810
+ "cancelled",
3811
+ "lost"
3812
+ ];
3813
+ function normalizeBackgroundStatus(value) {
3814
+ return BACKGROUND_STATUSES.includes(value) ? value : "running";
3815
+ }
3659
3816
  var SessionHub = class {
3660
3817
  client;
3661
3818
  sessions = /* @__PURE__ */ new Map();
@@ -3910,7 +4067,11 @@ var SessionHub = class {
3910
4067
  id: taskId,
3911
4068
  command: typeof task.command === "string" ? task.command : "",
3912
4069
  description: typeof task.description === "string" ? task.description : void 0,
3913
- status: task.status === "running" || task.status === "failed" ? task.status : "done",
4070
+ // Pass the server's status through unchanged. Collapsing it here
4071
+ // made subscribers see a successful-looking "done" for tasks the
4072
+ // REST API correctly reported as cancelled or lost.
4073
+ status: normalizeBackgroundStatus(task.status),
4074
+ failureReason: typeof task.failure_reason === "string" ? task.failure_reason : void 0,
3914
4075
  exitCode: typeof task.exit_code === "number" || task.exit_code === null ? task.exit_code : void 0,
3915
4076
  elapsedSeconds: typeof task.elapsed_seconds === "number" ? task.elapsed_seconds : 0,
3916
4077
  output: Array.isArray(task.output_preview) && task.output_preview.length > 0 ? task.output_preview.join("\n") : void 0
@@ -3953,7 +4114,7 @@ function resolveAuthToken(options) {
3953
4114
 
3954
4115
  // src/version.ts
3955
4116
  var SDK_NAME = "agent-client";
3956
- var SDK_VERSION = true ? "1.2.1-alpha.2" : "1.1.1";
4117
+ var SDK_VERSION = true ? "1.2.1-beta.1" : "1.1.1";
3957
4118
 
3958
4119
  // src/socket.ts
3959
4120
  function withSdkIdentity(auth) {
@@ -4406,6 +4567,7 @@ var SessionInfo = type({
4406
4567
  "model?": "string | null",
4407
4568
  "enable_thinking?": "boolean | null",
4408
4569
  "solution_id?": "string | null",
4570
+ "solution_ref?": "unknown",
4409
4571
  "biz_role_id?": "string | null",
4410
4572
  "solution?": "unknown",
4411
4573
  "plan_summary?": "string | null",