@blade-hq/agent-client 2610.0.0-beta.47 → 2610.0.0-beta.48
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 +11 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +115 -4
- package/dist/index.js.map +1 -1
- package/dist/polling-backoff.d.ts +11 -0
- package/dist/resources/chat-projects.d.ts +4 -0
- package/dist/session/hub.d.ts +1 -0
- package/dist/shared/auth-busy.d.ts +9 -0
- package/package.json +1 -1
- package/public-api.md +24 -1
package/README.md
CHANGED
|
@@ -502,6 +502,15 @@ PATCH / query / FormData / AbortSignal 等完整 HTTP 语义(否则不够用
|
|
|
502
502
|
> **安全约束**:`client.token` 只应发往 `baseUrl` 同源的接口。不要把它附加到
|
|
503
503
|
> 第三方域名的请求上——那等于把用户的访问凭据交给别人。
|
|
504
504
|
|
|
505
|
+
### 只读轮询退避
|
|
506
|
+
|
|
507
|
+
`new PollingBackoff(3000)` 为轮询维护独立退避状态,参数为正常间隔(大于 0、不超过 60 秒)。
|
|
508
|
+
请求成功后调用 `reset()`,失败后调用 `failed(error)`;`waitMs()` 返回剩余等待毫秒数,
|
|
509
|
+
`0` 表示可以请求,`false` 表示停止。HTTP 错误应传入保留响应头的 `BladeApiError`。
|
|
510
|
+
401/403 等确定性错误停止,网络/5xx 指数退避带抖动且最高 60 秒;`Retry-After`
|
|
511
|
+
可以要求更长等待,超出浏览器定时器范围时停止。策略自身不发送请求,调度器须传递
|
|
512
|
+
AbortSignal、在卸载时停止,并避免将它用于自动重放 POST 等有副作用的操作。
|
|
513
|
+
|
|
505
514
|
## headless:一次性问答
|
|
506
515
|
|
|
507
516
|
```ts
|
|
@@ -607,7 +616,7 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
607
616
|
- **SDK 身份**:`SDK_NAME`、`SDK_VERSION`
|
|
608
617
|
- **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
|
|
609
618
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
610
|
-
- **聊天项目资源(REST)**:`ChatProjectsResource`、`ChatProject`
|
|
619
|
+
- **聊天项目资源(REST)**:`ChatProjectsResource`、`ChatProject`(含 `delete` 永久删除)
|
|
611
620
|
- **会话资源(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`
|
|
612
621
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
613
622
|
- **会话状态机**:`SessionHub`、`SessionConnectOptions`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
@@ -615,4 +624,4 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
615
624
|
- **消息与投影协议**:`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`
|
|
616
625
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
617
626
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
|
618
|
-
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acknowledgeTurnEvents`、`hasChatRunEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`、`reconcileHistoricalUserTurns`
|
|
627
|
+
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`AuthBusyReconnect`、`authBusyRetryDelayMs`、`ClientProjectionBuilder`、`RawEvent`、`acknowledgeTurnEvents`、`hasChatRunEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`、`reconcileHistoricalUserTurns`
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { BladeClient } from "./blade-client";
|
|
2
2
|
export type { BladeClientOptions, UploadProgress } from "./blade-client";
|
|
3
3
|
export { BladeApiError } from "./rest";
|
|
4
|
+
export { PollingBackoff } from "./polling-backoff";
|
|
4
5
|
export type { LoginOptions, LoginResult, TokenStorageMode } from "./auth-login";
|
|
5
6
|
export { EMPTY_PLATFORM_ENDPOINTS, loadPlatformEndpoints, resolveServiceUrl, } from "./platform-endpoints";
|
|
6
7
|
export type { LoadPlatformEndpointsOptions, PlatformEndpoints, PlatformServiceName, } from "./platform-endpoints";
|
|
@@ -50,6 +51,7 @@ export { Task, TaskStatus } from "./schemas/task";
|
|
|
50
51
|
export type { BackgroundTask, BackgroundTaskStopResult } from "./schemas/background";
|
|
51
52
|
export { acceptedPostChatFollowupCompletesLatestRun, acknowledgeTurnEvents, ClientProjectionBuilder, } from "./shared/projection";
|
|
52
53
|
export type { RawEvent } from "./shared/projection";
|
|
54
|
+
export { AuthBusyReconnect, authBusyRetryDelayMs } from "./shared/auth-busy";
|
|
53
55
|
export { createSocket } from "./socket";
|
|
54
56
|
export type { CreateSocketOptions, TypedSocket } from "./socket";
|
|
55
57
|
export type { AsrAudioPayload } from "./types/socket-events";
|
package/dist/index.js
CHANGED
|
@@ -3053,6 +3053,50 @@ var ChatProjectsResource = class {
|
|
|
3053
3053
|
update(projectId, payload) {
|
|
3054
3054
|
return this.client.json("PATCH", `/api/chat-projects/${encodeURIComponent(projectId)}`, payload);
|
|
3055
3055
|
}
|
|
3056
|
+
delete(projectId) {
|
|
3057
|
+
return this.client.json("DELETE", `/api/chat-projects/${encodeURIComponent(projectId)}`);
|
|
3058
|
+
}
|
|
3059
|
+
};
|
|
3060
|
+
|
|
3061
|
+
// src/shared/auth-busy.ts
|
|
3062
|
+
var DEFAULT_RETRY_AFTER_SECONDS = 1;
|
|
3063
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
3064
|
+
function errorData(error) {
|
|
3065
|
+
if (typeof error !== "object" || error === null || !("data" in error)) return null;
|
|
3066
|
+
const data = error.data;
|
|
3067
|
+
return typeof data === "object" && data !== null ? data : null;
|
|
3068
|
+
}
|
|
3069
|
+
function authBusyRetryDelayMs(error) {
|
|
3070
|
+
const data = errorData(error);
|
|
3071
|
+
if (data?.code !== "auth_busy" || Number(data.status) !== 429) return null;
|
|
3072
|
+
const rawRetryAfter = data.retry_after;
|
|
3073
|
+
const seconds = rawRetryAfter == null || String(rawRetryAfter).trim() === "" ? Number.NaN : Number(rawRetryAfter);
|
|
3074
|
+
const delaySeconds = Number.isFinite(seconds) && seconds >= 0 ? seconds : DEFAULT_RETRY_AFTER_SECONDS;
|
|
3075
|
+
return Math.min(delaySeconds * 1e3, MAX_TIMER_DELAY_MS);
|
|
3076
|
+
}
|
|
3077
|
+
var AuthBusyReconnect = class {
|
|
3078
|
+
timer = null;
|
|
3079
|
+
get pending() {
|
|
3080
|
+
return this.timer !== null;
|
|
3081
|
+
}
|
|
3082
|
+
schedule(error, reconnect) {
|
|
3083
|
+
const delay = authBusyRetryDelayMs(error);
|
|
3084
|
+
if (delay === null) {
|
|
3085
|
+
this.cancel();
|
|
3086
|
+
return false;
|
|
3087
|
+
}
|
|
3088
|
+
this.cancel();
|
|
3089
|
+
this.timer = globalThis.setTimeout(() => {
|
|
3090
|
+
this.timer = null;
|
|
3091
|
+
reconnect();
|
|
3092
|
+
}, delay);
|
|
3093
|
+
return true;
|
|
3094
|
+
}
|
|
3095
|
+
cancel() {
|
|
3096
|
+
if (this.timer === null) return;
|
|
3097
|
+
globalThis.clearTimeout(this.timer);
|
|
3098
|
+
this.timer = null;
|
|
3099
|
+
}
|
|
3056
3100
|
};
|
|
3057
3101
|
|
|
3058
3102
|
// src/commands/registry.ts
|
|
@@ -5099,6 +5143,7 @@ var SessionHub = class {
|
|
|
5099
5143
|
connectionListeners = /* @__PURE__ */ new Set();
|
|
5100
5144
|
bound = false;
|
|
5101
5145
|
hasConnected = false;
|
|
5146
|
+
authBusyReconnect = new AuthBusyReconnect();
|
|
5102
5147
|
constructor(client) {
|
|
5103
5148
|
this.client = client;
|
|
5104
5149
|
}
|
|
@@ -5165,6 +5210,7 @@ var SessionHub = class {
|
|
|
5165
5210
|
/** 手动重连(例如登录态变化后)。 */
|
|
5166
5211
|
reconnect() {
|
|
5167
5212
|
this.ensureBound();
|
|
5213
|
+
this.authBusyReconnect.cancel();
|
|
5168
5214
|
const socket = this.client.socket();
|
|
5169
5215
|
socket.disconnect();
|
|
5170
5216
|
this.setConnection("connecting");
|
|
@@ -5172,11 +5218,13 @@ var SessionHub = class {
|
|
|
5172
5218
|
}
|
|
5173
5219
|
/** 断开连接(不清理 session 实例)。 */
|
|
5174
5220
|
disconnect() {
|
|
5221
|
+
this.authBusyReconnect.cancel();
|
|
5175
5222
|
this.client.socket().disconnect();
|
|
5176
5223
|
this.setConnection("disconnected");
|
|
5177
5224
|
}
|
|
5178
5225
|
/** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */
|
|
5179
5226
|
disposeAll() {
|
|
5227
|
+
this.authBusyReconnect.cancel();
|
|
5180
5228
|
this.bootstrapPending.clear();
|
|
5181
5229
|
for (const session of [...this.sessions.values()]) {
|
|
5182
5230
|
this.forceRelease(session);
|
|
@@ -5188,6 +5236,7 @@ var SessionHub = class {
|
|
|
5188
5236
|
* turn:* / chat:* 事件都会静默丢弃。
|
|
5189
5237
|
*/
|
|
5190
5238
|
_handleSocketReplaced() {
|
|
5239
|
+
this.authBusyReconnect.cancel();
|
|
5191
5240
|
this.bound = false;
|
|
5192
5241
|
this.setConnection("disconnected");
|
|
5193
5242
|
if (this.sessions.size === 0) return;
|
|
@@ -5240,6 +5289,9 @@ var SessionHub = class {
|
|
|
5240
5289
|
if (this.sessions.get(session.sessionId) === session) {
|
|
5241
5290
|
this.sessions.delete(session.sessionId);
|
|
5242
5291
|
}
|
|
5292
|
+
if (this.sessions.size === 0) {
|
|
5293
|
+
this.authBusyReconnect.cancel();
|
|
5294
|
+
}
|
|
5243
5295
|
;
|
|
5244
5296
|
this.client.socket().emit("session:unsubscribe", { session_id: session.sessionId });
|
|
5245
5297
|
return true;
|
|
@@ -5248,10 +5300,13 @@ var SessionHub = class {
|
|
|
5248
5300
|
forceRelease(session) {
|
|
5249
5301
|
this.holdCounts.delete(session.sessionId);
|
|
5250
5302
|
session.dispose();
|
|
5303
|
+
if (this.sessions.size === 0) {
|
|
5304
|
+
this.authBusyReconnect.cancel();
|
|
5305
|
+
}
|
|
5251
5306
|
}
|
|
5252
5307
|
ensureConnected() {
|
|
5253
5308
|
const socket = this.client.socket();
|
|
5254
|
-
if (socket.connected || socket.active) return;
|
|
5309
|
+
if (socket.connected || socket.active || this.authBusyReconnect.pending) return;
|
|
5255
5310
|
this.setConnection("connecting");
|
|
5256
5311
|
socket.connect();
|
|
5257
5312
|
}
|
|
@@ -5283,6 +5338,7 @@ var SessionHub = class {
|
|
|
5283
5338
|
this.bound = true;
|
|
5284
5339
|
const socket = this.client.socket();
|
|
5285
5340
|
socket.on("connect", () => {
|
|
5341
|
+
this.authBusyReconnect.cancel();
|
|
5286
5342
|
const isReconnect = this.hasConnected;
|
|
5287
5343
|
this.hasConnected = true;
|
|
5288
5344
|
this.setConnection("connected");
|
|
@@ -5292,8 +5348,24 @@ var SessionHub = class {
|
|
|
5292
5348
|
}
|
|
5293
5349
|
}
|
|
5294
5350
|
});
|
|
5295
|
-
socket.on("connect_error", () =>
|
|
5296
|
-
|
|
5351
|
+
socket.on("connect_error", (error) => {
|
|
5352
|
+
this.setConnection("disconnected");
|
|
5353
|
+
if (this.sessions.size === 0) {
|
|
5354
|
+
this.authBusyReconnect.cancel();
|
|
5355
|
+
return;
|
|
5356
|
+
}
|
|
5357
|
+
if (this.authBusyReconnect.schedule(error, () => {
|
|
5358
|
+
const current = this.client.socket();
|
|
5359
|
+
if (current !== socket || current.connected || current.active) return;
|
|
5360
|
+
this.setConnection("connecting");
|
|
5361
|
+
current.connect();
|
|
5362
|
+
})) return;
|
|
5363
|
+
this.authBusyReconnect.cancel();
|
|
5364
|
+
});
|
|
5365
|
+
socket.on("disconnect", () => {
|
|
5366
|
+
this.authBusyReconnect.cancel();
|
|
5367
|
+
this.setConnection("disconnected");
|
|
5368
|
+
});
|
|
5297
5369
|
socket.io.on("reconnect_attempt", () => this.setConnection("reconnecting"));
|
|
5298
5370
|
socket.on("turn:start", (data) => {
|
|
5299
5371
|
for (const session of this.route(data.session_id)) session._handleTurnStart(data);
|
|
@@ -5842,6 +5914,42 @@ function parseXhrHeaders(rawHeaders) {
|
|
|
5842
5914
|
return headers;
|
|
5843
5915
|
}
|
|
5844
5916
|
|
|
5917
|
+
// src/polling-backoff.ts
|
|
5918
|
+
var MAX_BACKOFF_MS = 6e4;
|
|
5919
|
+
var MAX_TIMER_MS = 2147483647;
|
|
5920
|
+
var PollingBackoff = class {
|
|
5921
|
+
constructor(intervalMs) {
|
|
5922
|
+
this.intervalMs = intervalMs;
|
|
5923
|
+
if (!Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > MAX_BACKOFF_MS) {
|
|
5924
|
+
throw new RangeError("Polling interval must be between 0 and 60000 ms");
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
intervalMs;
|
|
5928
|
+
failures = 0;
|
|
5929
|
+
nextAt = 0;
|
|
5930
|
+
reset() {
|
|
5931
|
+
this.failures = 0;
|
|
5932
|
+
this.nextAt = 0;
|
|
5933
|
+
}
|
|
5934
|
+
failed(error) {
|
|
5935
|
+
if (error instanceof Error && error.name === "AbortError" || error instanceof BladeApiError && error.status < 500 && error.status !== 408 && error.status !== 429) {
|
|
5936
|
+
this.nextAt = false;
|
|
5937
|
+
return;
|
|
5938
|
+
}
|
|
5939
|
+
this.failures = Math.min(this.failures + 1, 10);
|
|
5940
|
+
const ceiling = Math.min(MAX_BACKOFF_MS, this.intervalMs * 2 ** this.failures);
|
|
5941
|
+
const backoff = Math.max(this.intervalMs, ceiling * (0.5 + Math.random() * 0.5));
|
|
5942
|
+
const header = error instanceof BladeApiError ? error.response.headers.get("Retry-After")?.trim() : void 0;
|
|
5943
|
+
const retryAfter = header ? /^\d+$/.test(header) ? Number(header) * 1e3 : Date.parse(header) - Date.now() : 0;
|
|
5944
|
+
const delay = Math.max(backoff, Number.isNaN(retryAfter) ? 0 : retryAfter);
|
|
5945
|
+
this.nextAt = delay > MAX_TIMER_MS ? false : Date.now() + delay;
|
|
5946
|
+
}
|
|
5947
|
+
/** Zero means ready, false means stop, otherwise wait at least this many ms. */
|
|
5948
|
+
waitMs() {
|
|
5949
|
+
return this.nextAt === false ? false : Math.max(0, this.nextAt - Date.now());
|
|
5950
|
+
}
|
|
5951
|
+
};
|
|
5952
|
+
|
|
5845
5953
|
// src/platform-endpoints.ts
|
|
5846
5954
|
var PLATFORM_SERVICE_NAMES = [
|
|
5847
5955
|
"os",
|
|
@@ -5924,7 +6032,7 @@ function resolveServiceUrl(endpoints, name, path = "") {
|
|
|
5924
6032
|
|
|
5925
6033
|
// src/version.ts
|
|
5926
6034
|
var SDK_NAME = "agent-client";
|
|
5927
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
6035
|
+
var SDK_VERSION = true ? "2610.0.0-beta.48" : "1.1.1";
|
|
5928
6036
|
|
|
5929
6037
|
// src/commands/protocol.ts
|
|
5930
6038
|
function isCommandEnvelope(value) {
|
|
@@ -6026,6 +6134,7 @@ var Task = type2({
|
|
|
6026
6134
|
});
|
|
6027
6135
|
export {
|
|
6028
6136
|
AgentSession,
|
|
6137
|
+
AuthBusyReconnect,
|
|
6029
6138
|
BladeApiError,
|
|
6030
6139
|
BladeClient,
|
|
6031
6140
|
ChatProjectsResource,
|
|
@@ -6035,6 +6144,7 @@ export {
|
|
|
6035
6144
|
EMPTY_PLATFORM_ENDPOINTS,
|
|
6036
6145
|
LayoutType,
|
|
6037
6146
|
ModelsResource,
|
|
6147
|
+
PollingBackoff,
|
|
6038
6148
|
SDK_NAME,
|
|
6039
6149
|
SDK_VERSION,
|
|
6040
6150
|
SessionHub,
|
|
@@ -6045,6 +6155,7 @@ export {
|
|
|
6045
6155
|
TaskStatus,
|
|
6046
6156
|
acceptedPostChatFollowupCompletesLatestRun,
|
|
6047
6157
|
acknowledgeTurnEvents,
|
|
6158
|
+
authBusyRetryDelayMs,
|
|
6048
6159
|
buildMessageContent,
|
|
6049
6160
|
canToggleComputer,
|
|
6050
6161
|
chatErrorForDisplay,
|