@blade-hq/agent-client 2612.0.0-beta.20 → 2612.0.0-beta.22

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
@@ -162,17 +162,17 @@ const index = await client.sessions.getSessionTurnIndex(id) // SessionTurnIndex
162
162
  const first = index.items[0] // SessionTurnIndexItem
163
163
  ```
164
164
 
165
- 创建会话时可以绑定 Streamable HTTP MCP 来源;BA 会在创建成功前读取并保存工具列表,
166
- 来源此时必须可访问且接受创建请求中的 Bearer 凭据。之后沿用已发现的工具目录,
167
- 刷新来源时更新目录。默认 `exposure: "lazy"` 通过 `lazy_tool_list`、`lazy_tool_inspect`、
168
- `lazy_tool_run` 发现和调用工具;`exposure: "eager"` 会将 `include_tools` 允许的工具和完整
169
- 参数 schema 直接加入执行模式的模型工具列表,无需先 inspect。`eager_tools` 可在 lazy
170
- 来源中选出直接暴露的工具,也可指定 eager 来源中的优先工具。主运行和子智能体使用相同
171
- 策略,计划模式不加载。直接工具的名称为 `mcp_<来源>__<工具>_<hash>`,调用仍经 Go MCP
172
- dispatcher。会话 MCP 的可用工具名称按来源注入 `lazy_tool_catalog`,lazy 工具完整 schema
173
- 由 `lazy_tool_inspect({tool: "session:<source>/<tool>"})` 按需读取。每个运行最多直接加载 32 个工具、64 KiB 完整工具定义;
174
- 超预算的工具仍可通过
175
- `lazy_tool_inspect/lazy_tool_run` 使用。
165
+ 创建会话时可以绑定 Streamable HTTP MCP 来源,并用可选 `description` 提供用途说明。
166
+ 默认 `exposure: "lazy"` 只保存来源配置,创建时不连接 MCP;模型初始只看到来源名称和说明。
167
+ 通过 `lazy_tool_search({query: "所需能力", limit: 8})` 全局搜索并获得命中工具的完整标识、
168
+ 说明和参数 schema,再用 `lazy_tool_run` 调用。
169
+ 首次搜索发现工具,同一执行内复用成功目录;下一次执行重新发现。失败不缓存,也不返回部分成功。
170
+
171
+ `exposure: "eager"` 以及非空 `eager_tools` 保持创建时发现并保存目录:eager 将 `include_tools`
172
+ 允许的工具和完整 schema 直接加入执行模式的模型工具列表;`eager_tools` 可在 lazy 来源中选出
173
+ 直接暴露的工具,也可指定 eager 来源中的优先工具。主运行和子智能体使用相同策略,计划模式不加载。
174
+ 每个运行最多直接加载 32 个工具、64 KiB 完整工具定义;超预算的工具仍可通过搜索后 run 使用。
175
+ 显式会话 refresh 只重新发现 eager 来源目录。调用始终经 Go MCP dispatcher,继续校验当前身份和工具权限。
176
176
  Bearer 凭据只在创建或轮换时提交,查询不会返回它:
177
177
 
178
178
  ```ts
@@ -39,6 +39,7 @@ export declare class BladeClient {
39
39
  private readonly anonymousClients;
40
40
  private readonly toolProviders;
41
41
  private refreshPromise;
42
+ private cookieLogoutPending;
42
43
  private socketInstance;
43
44
  private readonly socketReplacementListeners;
44
45
  /** login() / setToken() 热挂载的令牌,优先级高于构造参数。 */
@@ -213,7 +213,7 @@ var ToolProvider = class {
213
213
 
214
214
  // src/version.ts
215
215
  var SDK_NAME = "agent-client";
216
- var SDK_VERSION = true ? "2612.0.0-beta.20" : "1.1.1";
216
+ var SDK_VERSION = true ? "2612.0.0-beta.22" : "1.1.1";
217
217
 
218
218
  // src/auth-login.ts
219
219
  function isAuthCallbackMessage(value) {
@@ -379,8 +379,8 @@ var AuthResource = class {
379
379
  getProviders() {
380
380
  return this.client.json("GET", "/api/auth/providers");
381
381
  }
382
- getMe() {
383
- return this.client.json("GET", "/api/auth/me");
382
+ getMe(options = {}) {
383
+ return this.client.jsonFromInit("/api/auth/me", { signal: options.signal });
384
384
  }
385
385
  logout() {
386
386
  return this.client.json("POST", "/api/auth/logout");
@@ -1105,8 +1105,8 @@ function snapshot(state, sequence, status) {
1105
1105
  first_token_ms: state.firstTokenMs,
1106
1106
  stream_duration_ms: state.streamDurationMs,
1107
1107
  first_token_delivery_ms: state.firstTokenDeliveryMs,
1108
- started_at: state.modelStartedAt ?? new Date(state.startedAt).toISOString(),
1109
- // 没有 payload 上报时用的是 loop:turn 的浏览器事件时间,标记出来供瀑布区分。
1108
+ started_at: state.modelStartedAt,
1109
+ // 未上报时不伪造服务器起点;浏览器时钟不能与服务器时钟混用。
1110
1110
  has_reported_timing: state.modelStartedAtReported,
1111
1111
  context_window: state.contextWindow,
1112
1112
  memory_refs: state.memoryRefs,
@@ -1859,6 +1859,7 @@ var ClientProjectionBuilder = class {
1859
1859
  return this.syncPatch(state);
1860
1860
  }
1861
1861
  applyFirstTokenDelivery(state, payload) {
1862
+ this.applyStreamTiming(state, payload);
1862
1863
  const firstTokenMs = payload.first_token_ms;
1863
1864
  if (state.firstTokenMs === null && typeof firstTokenMs === "number" && firstTokenMs >= 0) {
1864
1865
  state.firstTokenMs = Math.round(firstTokenMs);
@@ -2600,7 +2601,7 @@ function projectHistory(entries) {
2600
2601
  let content = isRecord(entry.message) ? entry.message.content : void 0;
2601
2602
  if (kind === "tool_result_archive") {
2602
2603
  const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0;
2603
- content = `<compaction-summary>
2604
+ content = typeof data.summary === "string" && data.summary ? data.summary : `<compaction-summary>
2604
2605
  \u5DF2\u5F52\u6863 ${archivedCount} \u4E2A\u5927\u578B\u5DE5\u5177\u7ED3\u679C\u3002
2605
2606
  </compaction-summary>`;
2606
2607
  }
@@ -3300,8 +3301,8 @@ var ModelsResource = class {
3300
3301
  this.client = client;
3301
3302
  }
3302
3303
  client;
3303
- list() {
3304
- return this.client.json("GET", "/api/config/models");
3304
+ list(options = {}) {
3305
+ return this.client.jsonFromInit("/api/config/models", { signal: options.signal });
3305
3306
  }
3306
3307
  };
3307
3308
 
@@ -3323,6 +3324,7 @@ var SessionInfo = type({
3323
3324
  "is_persistent?": "boolean",
3324
3325
  "initiator?": "'ui' | 'sdk' | 'unknown' | null",
3325
3326
  "is_headless?": "boolean",
3327
+ "scheduled_task_id?": "string",
3326
3328
  "viewer_role?": "'owner' | 'viewer'",
3327
3329
  "model?": "string | null",
3328
3330
  "enable_thinking?": "boolean | null",
@@ -3395,6 +3397,7 @@ var builtinSolutionIds = /* @__PURE__ */ new Set([
3395
3397
  "app-dev",
3396
3398
  "general_chat",
3397
3399
  "night_build",
3400
+ "scheduled_tasks",
3398
3401
  "skill_editor",
3399
3402
  "smart_bid",
3400
3403
  "solution_generate"
@@ -4254,6 +4257,20 @@ var SiteVisitsResource = class {
4254
4257
  }
4255
4258
  };
4256
4259
 
4260
+ // src/server-clock.ts
4261
+ var clocks = /* @__PURE__ */ new WeakMap();
4262
+ function syncServerTime(client, timestamp, receivedAt = performance.now()) {
4263
+ if (typeof timestamp !== "string") return;
4264
+ const serverTime = Date.parse(timestamp);
4265
+ if (!Number.isFinite(serverTime)) return;
4266
+ const current = getServerTime(client, receivedAt);
4267
+ clocks.set(client, { serverTime: Math.max(serverTime, current ?? serverTime), receivedAt });
4268
+ }
4269
+ function getServerTime(client, now = performance.now()) {
4270
+ const clock = client ? clocks.get(client) : void 0;
4271
+ return clock ? clock.serverTime + Math.max(0, now - clock.receivedAt) : null;
4272
+ }
4273
+
4257
4274
  // src/session/background.ts
4258
4275
  var BACKGROUND_STATUSES = [
4259
4276
  "starting",
@@ -7857,6 +7874,7 @@ var SessionHub = class {
7857
7874
  socket.on(
7858
7875
  "turn:events",
7859
7876
  (data, acknowledge) => {
7877
+ syncServerTime(this.client, data.server_time);
7860
7878
  acknowledgeTurnEvents(acknowledge);
7861
7879
  if (data.session_id && (this.statusWatchCounts.has(data.session_id) || this.sessions.has(data.session_id)) && data.events?.some((event) => event.type === "log:record")) {
7862
7880
  const delivery = this.statusCursor(data.session_id).consume(data.events ?? []);
@@ -8062,6 +8080,7 @@ var BladeClient = class _BladeClient {
8062
8080
  anonymousClients = /* @__PURE__ */ new Map();
8063
8081
  toolProviders = /* @__PURE__ */ new Set();
8064
8082
  refreshPromise = null;
8083
+ cookieLogoutPending = 0;
8065
8084
  socketInstance = null;
8066
8085
  socketReplacementListeners = /* @__PURE__ */ new Set();
8067
8086
  /** login() / setToken() 热挂载的令牌,优先级高于构造参数。 */
@@ -8287,24 +8306,31 @@ var BladeClient = class _BladeClient {
8287
8306
  }
8288
8307
  async fetch(method, path, init = {}, isRetry = false) {
8289
8308
  const url = this.buildUrl(path);
8290
- const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {
8291
- method,
8292
- body: init.body,
8293
- credentials: init.credentials ?? "include",
8294
- headers: this.buildHeaders(url, init.headers),
8295
- signal: init.signal
8296
- });
8297
- if (response.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {
8298
- const refreshed = await this.tryRefreshUnlessAborted(init.signal);
8299
- if (refreshed) {
8300
- return this.fetch(method, path, init, true);
8309
+ const isLogout = method === "POST" && url.pathname === this.buildUrl("/api/auth/logout").pathname && this.isSameBackendUrl(url);
8310
+ if (isLogout) this.cookieLogoutPending += 1;
8311
+ try {
8312
+ if (isLogout) await this.refreshPromise;
8313
+ const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {
8314
+ method,
8315
+ body: init.body,
8316
+ credentials: init.credentials ?? "include",
8317
+ headers: this.buildHeaders(url, init.headers),
8318
+ signal: init.signal
8319
+ });
8320
+ if (response.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {
8321
+ const refreshed = await this.tryRefreshUnlessAborted(init.signal);
8322
+ if (refreshed) {
8323
+ return this.fetch(method, path, init, true);
8324
+ }
8301
8325
  }
8326
+ if (init.expectOk !== false && !response.ok) {
8327
+ const detail = await extractErrorDetail(response);
8328
+ throw decorateAuthError(new BladeApiError(response, detail));
8329
+ }
8330
+ return response;
8331
+ } finally {
8332
+ if (isLogout) this.cookieLogoutPending -= 1;
8302
8333
  }
8303
- if (init.expectOk !== false && !response.ok) {
8304
- const detail = await extractErrorDetail(response);
8305
- throw decorateAuthError(new BladeApiError(response, detail));
8306
- }
8307
- return response;
8308
8334
  }
8309
8335
  buildAuthedUrl(path) {
8310
8336
  const url = buildBackendUrl(this.options.baseUrl, path);
@@ -8372,7 +8398,7 @@ var BladeClient = class _BladeClient {
8372
8398
  }
8373
8399
  }
8374
8400
  async tryRefresh() {
8375
- if (this.options.anonymousSessionId) return false;
8401
+ if (this.options.anonymousSessionId || this.cookieLogoutPending > 0) return false;
8376
8402
  if (this.refreshPromise) {
8377
8403
  return this.refreshPromise;
8378
8404
  }
@@ -8554,6 +8580,8 @@ export {
8554
8580
  isEntryGoneError,
8555
8581
  PluginsResource,
8556
8582
  ChatGroupsResource,
8583
+ syncServerTime,
8584
+ getServerTime,
8557
8585
  authBusyRetryDelayMs,
8558
8586
  AuthBusyReconnect,
8559
8587
  prependOlder,
@@ -8600,4 +8628,4 @@ export {
8600
8628
  createSocket,
8601
8629
  BladeClient
8602
8630
  };
8603
- //# sourceMappingURL=chunk-2VIJBVAC.js.map
8631
+ //# sourceMappingURL=chunk-C3DI7OI7.js.map