@blade-hq/agent-client 2610.0.0-beta.70 → 2610.0.0-beta.71
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 +14 -2
- package/dist/blade-client.d.ts +8 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +204 -32
- package/dist/index.js.map +1 -1
- package/dist/resources/sessions.d.ts +34 -4
- package/dist/schemas/message-utils.d.ts +8 -0
- package/dist/session/agent-session.d.ts +57 -4
- package/package.json +1 -1
- package/public-api.md +179 -2
package/README.md
CHANGED
|
@@ -169,8 +169,16 @@ await client.sessions.deleteSession(id)
|
|
|
169
169
|
await client.sessions.getSessionTurns(id) // 历史消息(投影格式,与实时流同构)
|
|
170
170
|
const page = await client.sessions.getSessionTurnsPage(id) // 聊天首屏 recent page
|
|
171
171
|
await client.sessions.getSessionTurnsPage(id, { before: page.nextBefore! })
|
|
172
|
+
// 从某条用户发言定位到最新(消息导航点窗口外的发言):调用参数是 SessionTurnsQuery
|
|
173
|
+
await client.sessions.getSessionTurnsPage(id, { fromEntryId: "entry-id" })
|
|
174
|
+
// 当前分支上全部可导航的用户发言目录(entry_id + 标题 + 时间,不含消息体)
|
|
175
|
+
const index = await client.sessions.getSessionTurnIndex(id) // SessionTurnIndex
|
|
176
|
+
const first = index.items[0] // SessionTurnIndexItem
|
|
172
177
|
```
|
|
173
178
|
|
|
179
|
+
`SessionTurnsQuery` 的 `before` 与 `fromEntryId` 互斥;定位命中不了当前分支时服务端返回
|
|
180
|
+
404 / 409,而不是空窗口。目录的 `entryId` 与 `/turns` 的 `turn_id` 同源,可直接当 `before` 游标。
|
|
181
|
+
|
|
174
182
|
会话插件可通过 `client.sessions.listSessionPlugins(id)` 查询,并用
|
|
175
183
|
`client.sessions.setSessionPluginActivation(id, name, active)` 切换当前会话。列表项为 `SessionPlugin`;修改结果为 `SessionPluginActivation`,只返回选择和准备状态,安装事实需从列表获取。
|
|
176
184
|
|
|
@@ -736,12 +744,16 @@ HTML 一律判无效);`isInternalStatusToolUiCard` 识别内部「阶段进
|
|
|
736
744
|
- **插件目录(REST,无会话)**:`PluginsResource`、`PluginCatalogEntry`(`client.plugins`)。首页这类还没有会话的界面用它读名称、业务名与图标 token
|
|
737
745
|
- **账号电脑目录**:`AccountComputer`、`AccountComputerList`(`client.computers.listAccount()`,只读账号事实,不含会话授权)
|
|
738
746
|
- **全站访问统计(REST)**:`SiteVisitsResource`、`SiteVisitsSummary`(`client.siteVisits.record()` 上报一次页面访问、`client.siteVisits.summary()` 只读快照)。这两个操作走独立匿名传输:不带 bearer、不触发 401 登录刷新,只依赖匿名访客 Cookie,供内置 Web 同源使用。
|
|
739
|
-
- **会话资源(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`
|
|
747
|
+
- **会话资源(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`、`PrimarySkillStageSpec`、`PrimarySkillStepSpec`、`SkillEditorTemplateId`、`SessionSearchMatch`
|
|
748
|
+
- **会话历史取数**:`SessionTurnsQuery`、`SessionTurnsPage`、`SessionTurnIndex`、`SessionTurnIndexItem`、`isEntryGoneError`(`isEntryGoneError` 区分"这条发言已经不在当前分支上"与"这次没取到":前者说明 `fromEntryId` 定位目标失效,后者只说明本次请求失败)
|
|
740
749
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
741
750
|
- **会话状态机**:`SessionHub`、`SessionConnectOptions`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
751
|
+
- **静态历史会话**:`AgentSession.fromTurns(sessionId, turns)` 构造的会话 `isStatic` 为 true——它没有目录接口,宿主拿已加载窗口推导航条目(`turnNavItemsFromMessages`);真实会话不要这么做,timeline 被重写后窗口里还是旧分支的发言,那些 entry id 已经点不到了
|
|
752
|
+
- **长会话跨页定位**:`AgentSession.locateEntry(entryId)`(按稳定 `entry_id` 取"从它往后"的窗口)、`AgentSession.cancelPendingLocate()`(作废在途的那次定位;它只中止定位自己的请求,不牵动运行结束 / 重连的权威刷新)。权威刷新(运行结束 / 重连补数 / 翻页之后的对账)不另记状态:一律按**当前窗口第一条发言**取窗口,那条已经不在分支上(404 / 409)时回落最新一页;`sessions.getSessionTurnIndex(sessionId)` 给出可导航的用户发言目录(`SessionTurnIndex` / `SessionTurnIndexItem`),`getSessionTurnsPage({ fromEntryId })` 与它共用同一份分支投影
|
|
742
753
|
- **会话消息队列**:`SessionQueueSnapshot`、`QueuedMessage`、`QueuedMessageStatus`、`QueueAck`、`QueueOperationResult`、`EMPTY_SESSION_QUEUE`、`isSessionQueueSnapshot`、`shouldApplySnapshot`、`parseQueueAck`、`canEditQueuedMessage`、`canCancelQueuedMessage`、`canDeliverQueuedMessage`、`queuedMessageStatusLabel`、`queuePauseReasonLabel`
|
|
743
754
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
744
|
-
-
|
|
755
|
+
- **流式 wire 事件(自定义渲染用)**:`ContentDelta`、`ToolCallCreated`、`ToolCallArgumentsDelta`、`ToolResultDelta`、`ToolResultDone`、`LlmResponseDone`、`ChatEnd`、`SystemError`、`SessionStatusEvent`。它们描述 socket 上一帧帧到达的内容,只有自己接管流式拼装时才需要
|
|
756
|
+
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`ContextProjectionData`、`ContextProjectionFields`、`ContextDisplayState`、`ContextGroupDisplayState`、`ContextAction`、`ContextSourceInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`ToolCallProjection`、`PendingQuestionRef`、`RunTiming`、`inferToolStatus`、`contextProjectionData`、`getContextDisplayState`、`getContextGroupDisplayState`、`groupAdjacentContextRuns`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
745
757
|
- **MCP Apps 留档与卡片判定**:`McpAppData`、`isMcpAppData`、`McpAppContextState`、`McpAppContextUpdate`、`ToolUiCard`、`ToolUiCardContentType`、`InlineToolUiCardEntry`、`PreviewToolUiCardEntry`、`isToolUiCard`、`resolveToolUiCardContent`、`buildToolUiCardKey`、`isInternalStatusToolUiCard`、`isAppDevToolUiCard`、`collectInlineToolUiCards`、`collectPreviewToolUiCards`(`McpAppContextState` / `McpAppContextUpdate` 配合 `sessions.getMcpAppContext` / `sessions.updateMcpAppContext`:App 保存的状态在下一个新运行才进入模型上下文)
|
|
746
758
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
747
759
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
package/dist/blade-client.d.ts
CHANGED
|
@@ -99,6 +99,14 @@ export declare class BladeClient {
|
|
|
99
99
|
private isSameBackendUrl;
|
|
100
100
|
private shouldRefreshFor401;
|
|
101
101
|
private hasExplicitBearerToken;
|
|
102
|
+
/**
|
|
103
|
+
* 等一次令牌刷新,但调用方中止请求时不再等下去。
|
|
104
|
+
*
|
|
105
|
+
* 刷新本身是共享的(`refreshPromise`,别的请求也在等它),这里只是让这次已被取消的
|
|
106
|
+
* 请求尽早结束——否则它会一直挂在调用方(定位)的串行队列里,用户改选的新目标要等到
|
|
107
|
+
* 刷新结束才轮得到。
|
|
108
|
+
*/
|
|
109
|
+
private tryRefreshUnlessAborted;
|
|
102
110
|
private tryRefresh;
|
|
103
111
|
private resolveTokenForUrl;
|
|
104
112
|
private resolveRestToken;
|
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 { isEntryGoneError } from "./resources/sessions";
|
|
4
5
|
export { PollingBackoff } from "./polling-backoff";
|
|
5
6
|
export type { LoginOptions, LoginResult, TokenStorageMode } from "./auth-login";
|
|
6
7
|
export { EMPTY_PLATFORM_ENDPOINTS, loadPlatformEndpoints, resolveServiceUrl, } from "./platform-endpoints";
|
|
@@ -40,13 +41,15 @@ export { PluginsResource } from "./resources/plugins";
|
|
|
40
41
|
export type { PluginCatalogEntry } from "./resources/plugins";
|
|
41
42
|
export type { SiteVisitsResource, SiteVisitsSummary } from "./resources/site-visits";
|
|
42
43
|
export { hasChatRunEvent } from "./shared/projection";
|
|
43
|
-
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, HistoricalCommand, SessionContextStats, SessionHistory, SessionTurnsPage, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
44
|
+
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, HistoricalCommand, SessionContextStats, SessionHistory, SessionTurnsPage, SessionTurnsQuery, SessionTurnIndex, SessionTurnIndexItem, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
44
45
|
export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
|
|
46
|
+
export { inferToolStatus } from "./schemas/message";
|
|
47
|
+
export type { ChatEnd, ContentDelta, LlmResponseDone, SessionStatusEvent, SystemError, ToolCallArgumentsDelta, ToolCallCreated, ToolResultDelta, ToolResultDone, } from "./schemas/event";
|
|
45
48
|
export { buildMessageContent, chatErrorForDisplay, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
|
|
46
49
|
export { contextProjectionData, getContextDisplayState, getContextGroupDisplayState, groupAdjacentContextRuns, } from "./schemas/context";
|
|
47
50
|
export type { ContextAction, ContextDisplayState, ContextGroupDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
|
|
48
51
|
export type { ParsedTextAttachment, ParsedTextContext, SkillMentionAvailability, } from "./schemas/message-utils";
|
|
49
|
-
export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PostChatFollowup, TurnProjection, } from "./schemas/projection";
|
|
52
|
+
export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PendingQuestionRef, PostChatFollowup, RunTiming, ToolCallProjection, TurnProjection, } from "./schemas/projection";
|
|
50
53
|
export { latestPostChatFollowup } from "./schemas/projection-utils";
|
|
51
54
|
export { buildToolUiCardKey, collectInlineToolUiCards, collectPreviewToolUiCards, isAppDevToolUiCard, isInternalStatusToolUiCard, isToolUiCard, resolveToolUiCardContent, } from "./shared/tool-ui-card";
|
|
52
55
|
export type { InlineToolUiCardEntry, PreviewToolUiCardEntry, ToolUiCard, ToolUiCardContentType, } from "./shared/tool-ui-card";
|
|
@@ -54,7 +57,7 @@ export { prependOlder, replaceWindow } from "./session/history-page";
|
|
|
54
57
|
export type { LiveRevisionState } from "./session/history-page";
|
|
55
58
|
export { DEFAULT_REPLAY_SPEED } from "./schemas/session";
|
|
56
59
|
export { SessionInfo, SessionStatus } from "./schemas/session";
|
|
57
|
-
export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, ReplayPreview, ReplaySpeed, ReplayState, SessionDetail, SessionPortMapping,
|
|
60
|
+
export type { ModeId, PrimarySkillParallelMode, PrimarySkillSnapshot, PrimarySkillStageSpec, PrimarySkillStepSpec, PublishedSolutionRef, ReplayPreview, ReplaySpeed, ReplayState, SessionDetail, SessionPortMapping, SessionSearchMatch, SkillEditorTemplateId, TemplateId, } from "./schemas/session";
|
|
58
61
|
export { LayoutType } from "./schemas/solution";
|
|
59
62
|
export type { BizRole, Solution, SolutionAppField, SolutionAppState, SolutionAppUiConfig, } from "./schemas/solution";
|
|
60
63
|
export { Task, TaskStatus } from "./schemas/task";
|
package/dist/index.js
CHANGED
|
@@ -2596,6 +2596,10 @@ function findLatestAssistant(turns, loopId) {
|
|
|
2596
2596
|
}
|
|
2597
2597
|
|
|
2598
2598
|
// src/resources/sessions.ts
|
|
2599
|
+
function isEntryGoneError(error) {
|
|
2600
|
+
const status = error?.status;
|
|
2601
|
+
return status === 404 || status === 409;
|
|
2602
|
+
}
|
|
2599
2603
|
function toCreateSessionPayload(request) {
|
|
2600
2604
|
const solutionRef = request.solution_ref ?? externalSolutionRef(request.solution_id);
|
|
2601
2605
|
return {
|
|
@@ -2932,18 +2936,36 @@ var SessionsResource = class {
|
|
|
2932
2936
|
);
|
|
2933
2937
|
return projectHistory(entries);
|
|
2934
2938
|
}
|
|
2935
|
-
async getSessionTurnsPage(sessionId, options = {}) {
|
|
2939
|
+
async getSessionTurnsPage(sessionId, options = {}, init = {}) {
|
|
2936
2940
|
const query = new URLSearchParams();
|
|
2937
2941
|
if (options.limit !== void 0) query.set("limit", String(options.limit));
|
|
2938
2942
|
if (options.before !== void 0) query.set("before", options.before);
|
|
2943
|
+
if (options.fromEntryId !== void 0) query.set("from_entry_id", options.fromEntryId);
|
|
2939
2944
|
const suffix = query.size ? `?${query}` : "";
|
|
2940
|
-
const page = await this.client.
|
|
2945
|
+
const page = await this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/turns${suffix}`, init);
|
|
2941
2946
|
return {
|
|
2942
2947
|
turns: page.turns,
|
|
2943
2948
|
nextBefore: page.next_before,
|
|
2944
2949
|
currentMode: page.current_mode
|
|
2945
2950
|
};
|
|
2946
2951
|
}
|
|
2952
|
+
/**
|
|
2953
|
+
* 当前分支上可导航的用户发言目录(消息导航侧栏)。
|
|
2954
|
+
*
|
|
2955
|
+
* 只回 id、标题和时间:侧栏要列的是**整条会话**的发言,而窗口外的发言 id 只能
|
|
2956
|
+
* 从服务端拿;消息体仍然走 `/turns`。
|
|
2957
|
+
*/
|
|
2958
|
+
async getSessionTurnIndex(sessionId) {
|
|
2959
|
+
const index = await this.client.json("GET", `/api/sessions/${encodeURIComponent(sessionId)}/turn-index`);
|
|
2960
|
+
return {
|
|
2961
|
+
sessionId: index.session_id,
|
|
2962
|
+
items: index.items.map((item) => ({
|
|
2963
|
+
entryId: item.entry_id,
|
|
2964
|
+
preview: item.preview,
|
|
2965
|
+
createdAt: item.created_at
|
|
2966
|
+
}))
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2947
2969
|
getMcpAppContext(sessionId, sourceId, init) {
|
|
2948
2970
|
return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/context`, init);
|
|
2949
2971
|
}
|
|
@@ -4209,12 +4231,12 @@ function orderTurns(turns) {
|
|
|
4209
4231
|
return turns;
|
|
4210
4232
|
}
|
|
4211
4233
|
function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
4212
|
-
return reconcileUserTurns(currentTurns, incomingTurns, true);
|
|
4234
|
+
return reconcileUserTurns(currentTurns, incomingTurns, true, false);
|
|
4213
4235
|
}
|
|
4214
4236
|
function reconcileHistoricalUserTurns(currentTurns, incomingTurns) {
|
|
4215
|
-
return reconcileUserTurns(currentTurns, incomingTurns, false);
|
|
4237
|
+
return reconcileUserTurns(currentTurns, incomingTurns, false, true);
|
|
4216
4238
|
}
|
|
4217
|
-
function reconcileUserTurns(currentTurns, incomingTurns, allowLiveFallback) {
|
|
4239
|
+
function reconcileUserTurns(currentTurns, incomingTurns, allowLiveFallback, keepUnclaimedOptimistic) {
|
|
4218
4240
|
const preservedTurns = preserveClientRenderIds(currentTurns, incomingTurns);
|
|
4219
4241
|
const optimisticUserTurns = currentTurns.filter(
|
|
4220
4242
|
(turn) => turn.role === "user" && (turn.kind ?? "message") === "message" && turn.turn_id.startsWith("local-user-")
|
|
@@ -4242,7 +4264,13 @@ function reconcileUserTurns(currentTurns, incomingTurns, allowLiveFallback) {
|
|
|
4242
4264
|
}
|
|
4243
4265
|
return turn;
|
|
4244
4266
|
});
|
|
4245
|
-
|
|
4267
|
+
const result = claimedOptimisticIds.size === 0 ? reconciled : reconciled.filter((turn) => !claimedOptimisticIds.has(turn.turn_id));
|
|
4268
|
+
if (!keepUnclaimedOptimistic) return result;
|
|
4269
|
+
const resultIds = new Set(result.map((turn) => turn.turn_id));
|
|
4270
|
+
const unclaimedOptimisticTurns = optimisticUserTurns.filter(
|
|
4271
|
+
(turn) => !claimedOptimisticIds.has(turn.turn_id) && !resultIds.has(turn.turn_id)
|
|
4272
|
+
);
|
|
4273
|
+
return unclaimedOptimisticTurns.length === 0 ? result : orderTurns([...result, ...unclaimedOptimisticTurns]);
|
|
4246
4274
|
}
|
|
4247
4275
|
function isUserConfirmation(turn) {
|
|
4248
4276
|
return turn.role === "user" && (turn.kind ?? "message") === "message" || turn.blocks.some((block) => block.type === "ask_user_answer");
|
|
@@ -4350,7 +4378,7 @@ function upsertTurn(state, turn) {
|
|
|
4350
4378
|
} else {
|
|
4351
4379
|
existing.push(nextTurn);
|
|
4352
4380
|
}
|
|
4353
|
-
return withTurns(state, existing);
|
|
4381
|
+
return withTurns({ ...state, turns: existing }, existing);
|
|
4354
4382
|
}
|
|
4355
4383
|
function applyTurnPatch(state, patch) {
|
|
4356
4384
|
const turn = patch.data.turn;
|
|
@@ -4487,6 +4515,10 @@ var AgentSession = class _AgentSession {
|
|
|
4487
4515
|
subscriptionQueue = Promise.resolve();
|
|
4488
4516
|
replaceQueue = Promise.resolve();
|
|
4489
4517
|
timelineEpoch = 0;
|
|
4518
|
+
/** 定位请求的流水号:被后一次选择取代的那次定位不再提交窗口(见 locateEntry)。 */
|
|
4519
|
+
locateToken = 0;
|
|
4520
|
+
/** 在途那次定位的请求句柄。**只**服务定位:权威刷新不共用它(见 cancelPendingLocate)。 */
|
|
4521
|
+
locateAbort = null;
|
|
4490
4522
|
pagingGeneration = 0;
|
|
4491
4523
|
liveRevision = 0;
|
|
4492
4524
|
modeRevision = 0;
|
|
@@ -4522,11 +4554,19 @@ var AgentSession = class _AgentSession {
|
|
|
4522
4554
|
seenToolCallIds = /* @__PURE__ */ new Set();
|
|
4523
4555
|
finishedToolCallIds = /* @__PURE__ */ new Set();
|
|
4524
4556
|
emittedMessageTurnIds = /* @__PURE__ */ new Set();
|
|
4525
|
-
constructor(sessionId, runtime, connection) {
|
|
4557
|
+
constructor(sessionId, runtime, connection, options = {}) {
|
|
4526
4558
|
this.sessionId = sessionId;
|
|
4527
4559
|
this.runtime = runtime;
|
|
4528
4560
|
this.state = { ...createInitialSessionState(sessionId), connection };
|
|
4561
|
+
this.isStatic = options.staticHistory === true;
|
|
4529
4562
|
}
|
|
4563
|
+
/**
|
|
4564
|
+
* 静态历史(分享页 / `fromTurns`):没有目录接口,也**没有**"目录还没到位"这个中间态。
|
|
4565
|
+
*
|
|
4566
|
+
* 宿主据此决定要不要拿已加载窗口当兜底条目——真实会话在 timeline 被重写后,窗口里还是
|
|
4567
|
+
* 旧分支的发言,拿它兜底会把已经失效的 entry id 重新摆到轨道上,点了必然找不到。
|
|
4568
|
+
*/
|
|
4569
|
+
isStatic;
|
|
4530
4570
|
/** 从一份静态 turn 快照构造只展示历史的会话(例如公开分享页)。 */
|
|
4531
4571
|
static fromTurns(sessionId, turns) {
|
|
4532
4572
|
const readonlyError = () => {
|
|
@@ -4539,6 +4579,8 @@ var AgentSession = class _AgentSession {
|
|
|
4539
4579
|
emitWithAck: async () => readonlyError(),
|
|
4540
4580
|
ensureConnected: readonlyError,
|
|
4541
4581
|
fetchTurnsPage: async () => ({ turns, nextBefore: null, currentMode: "executing" }),
|
|
4582
|
+
// 静态会话(分享页)没有会话目录接口,宿主用已加载的历史兜底条目。
|
|
4583
|
+
fetchTurnIndex: async () => ({ sessionId, items: [] }),
|
|
4542
4584
|
fetchCommands: async () => [],
|
|
4543
4585
|
// 静态历史没有回放身份可言,给个空详情即可,不要抛错——_bootstrap
|
|
4544
4586
|
// 不会跑到这里,但保持只读语义一致。
|
|
@@ -4550,7 +4592,8 @@ var AgentSession = class _AgentSession {
|
|
|
4550
4592
|
attachAppCli: async () => readonlyError(),
|
|
4551
4593
|
onDispose: () => true
|
|
4552
4594
|
},
|
|
4553
|
-
"connected"
|
|
4595
|
+
"connected",
|
|
4596
|
+
{ staticHistory: true }
|
|
4554
4597
|
);
|
|
4555
4598
|
session.state = {
|
|
4556
4599
|
...withTurns(session.state, turns),
|
|
@@ -4578,7 +4621,7 @@ var AgentSession = class _AgentSession {
|
|
|
4578
4621
|
const epoch = this.timelineEpoch;
|
|
4579
4622
|
const generation = this.pagingGeneration;
|
|
4580
4623
|
this.update((state) => ({ ...state, loadingOlder: true }));
|
|
4581
|
-
const request = this.runtime.fetchTurnsPage(this.sessionId, before).then((page) => {
|
|
4624
|
+
const request = this.runtime.fetchTurnsPage(this.sessionId, { before }).then((page) => {
|
|
4582
4625
|
if (epoch !== this.timelineEpoch || generation !== this.pagingGeneration || this.state.nextBefore !== before) return;
|
|
4583
4626
|
options.beforeCommit?.();
|
|
4584
4627
|
this.update((state) => ({
|
|
@@ -4586,10 +4629,11 @@ var AgentSession = class _AgentSession {
|
|
|
4586
4629
|
nextBefore: page.nextBefore,
|
|
4587
4630
|
loadingOlder: false
|
|
4588
4631
|
}));
|
|
4589
|
-
}).catch((error) => {
|
|
4632
|
+
}).catch(async (error) => {
|
|
4590
4633
|
if (isCursorInvalidError(error) && epoch === this.timelineEpoch && generation === this.pagingGeneration && this.state.nextBefore === before) {
|
|
4591
|
-
this.
|
|
4592
|
-
|
|
4634
|
+
this.invalidateTimeline();
|
|
4635
|
+
await this.replaceFromHistory();
|
|
4636
|
+
return;
|
|
4593
4637
|
}
|
|
4594
4638
|
}).finally(() => {
|
|
4595
4639
|
if (this.olderPending !== request) return;
|
|
@@ -4599,6 +4643,64 @@ var AgentSession = class _AgentSession {
|
|
|
4599
4643
|
this.olderPending = request;
|
|
4600
4644
|
return request;
|
|
4601
4645
|
}
|
|
4646
|
+
/**
|
|
4647
|
+
* 定位到一条窗口外的历史发言:请服务端返回"从这条发言到最新"的窗口并整窗替换。
|
|
4648
|
+
*
|
|
4649
|
+
* 返回 false 表示这次定位没有落地(请求失败,或期间 timeline 被重写、会话已释放),
|
|
4650
|
+
* 当前窗口保持不变,调用方可以原样重试。已加载的发言不要走这里——宿主直接滚动,
|
|
4651
|
+
* 一次网络请求都不该发。
|
|
4652
|
+
*/
|
|
4653
|
+
async locateEntry(entryId) {
|
|
4654
|
+
const token = ++this.locateToken;
|
|
4655
|
+
const controller = new AbortController();
|
|
4656
|
+
this.locateAbort?.abort();
|
|
4657
|
+
this.locateAbort = controller;
|
|
4658
|
+
try {
|
|
4659
|
+
return await this.replaceFromHistory({
|
|
4660
|
+
suppressErrors: false,
|
|
4661
|
+
fromEntryId: entryId,
|
|
4662
|
+
signal: controller.signal,
|
|
4663
|
+
isStale: () => this.locateToken !== token
|
|
4664
|
+
});
|
|
4665
|
+
} catch {
|
|
4666
|
+
return false;
|
|
4667
|
+
} finally {
|
|
4668
|
+
if (this.locateAbort === controller) this.locateAbort = null;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
/**
|
|
4672
|
+
* 取消在途定位:用户改选了另一条发言(哪怕那条已经加载、不需要请求),
|
|
4673
|
+
* 先前那次定位既不该再落地,也不该继续占着替换队列——排队中的下一次定位
|
|
4674
|
+
* 不然要等它跑完(用户看到的是"点了新目标一直转圈")。
|
|
4675
|
+
*
|
|
4676
|
+
* **只**中止定位自己的请求:权威刷新(运行结束 / 重连补数)不共用这个 controller,
|
|
4677
|
+
* 否则"运行刚结束时点一下侧栏"就会把终态对账一起中止,流式与历史对不上。
|
|
4678
|
+
*/
|
|
4679
|
+
cancelPendingLocate() {
|
|
4680
|
+
this.locateToken += 1;
|
|
4681
|
+
this.locateAbort?.abort();
|
|
4682
|
+
this.locateAbort = null;
|
|
4683
|
+
}
|
|
4684
|
+
/**
|
|
4685
|
+
* timeline 被整体改写(rewind / checkout / 释放):推进纪元,并把在途定位请求一并中止
|
|
4686
|
+
* ——它已经属于旧 timeline,却还占着替换队列,会让改写后的权威窗口排在后面等它跑完。
|
|
4687
|
+
* 作废号仍然保留:中止只是让它更早结束。
|
|
4688
|
+
*/
|
|
4689
|
+
invalidateTimeline() {
|
|
4690
|
+
this.timelineEpoch += 1;
|
|
4691
|
+
this.locateAbort?.abort();
|
|
4692
|
+
this.locateAbort = null;
|
|
4693
|
+
}
|
|
4694
|
+
/**
|
|
4695
|
+
* 拉取当前分支的用户发言目录(消息导航侧栏用)。
|
|
4696
|
+
*
|
|
4697
|
+
* 不在这里缓存:什么时候该刷新只有调用方知道(会话切换、历史被替换、新发言),
|
|
4698
|
+
* 缓存只会让旧条目在 rewind 之后继续可点。
|
|
4699
|
+
*/
|
|
4700
|
+
async loadTurnIndex() {
|
|
4701
|
+
const index = await this.runtime.fetchTurnIndex(this.sessionId);
|
|
4702
|
+
return index.items;
|
|
4703
|
+
}
|
|
4602
4704
|
/** 订阅状态变化。返回取消订阅函数。 */
|
|
4603
4705
|
subscribe(listener) {
|
|
4604
4706
|
this.listeners.add(listener);
|
|
@@ -4847,7 +4949,7 @@ var AgentSession = class _AgentSession {
|
|
|
4847
4949
|
whatif: options.whatif,
|
|
4848
4950
|
replay_decision: options.replayDecision,
|
|
4849
4951
|
app_context: appContext,
|
|
4850
|
-
kb_ids: options.kbIds
|
|
4952
|
+
kb_ids: options.kbIds,
|
|
4851
4953
|
// 运行中提交不必由客户端挑命令:服务端按会话运行状态决定直接执行还是入队。
|
|
4852
4954
|
queue_when_running: options.queueWhenRunning === true
|
|
4853
4955
|
};
|
|
@@ -4912,10 +5014,8 @@ var AgentSession = class _AgentSession {
|
|
|
4912
5014
|
this.pendingReplayMode = void 0;
|
|
4913
5015
|
this.pendingReplayKbIds = void 0;
|
|
4914
5016
|
this.update((current) => {
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
current.turns.filter((turn) => turn.turn_id !== optimisticTurnId)
|
|
4918
|
-
) : current;
|
|
5017
|
+
const filtered = optimisticTurnId ? current.turns.filter((turn) => turn.turn_id !== optimisticTurnId) : current.turns;
|
|
5018
|
+
let next = optimisticTurnId ? withTurns({ ...current, turns: filtered }, filtered) : current;
|
|
4919
5019
|
const toolCallId = askUserAnswer && typeof askUserAnswer.tool_call_id === "string" ? askUserAnswer.tool_call_id : null;
|
|
4920
5020
|
if (toolCallId && next.askAnswers[toolCallId] === optimisticAskAnswer) {
|
|
4921
5021
|
const askAnswers = { ...next.askAnswers };
|
|
@@ -5001,7 +5101,7 @@ var AgentSession = class _AgentSession {
|
|
|
5001
5101
|
if (this.disposed) return;
|
|
5002
5102
|
if (!this.runtime.onDispose(this)) return;
|
|
5003
5103
|
this.disposed = true;
|
|
5004
|
-
this.
|
|
5104
|
+
this.invalidateTimeline();
|
|
5005
5105
|
this.invalidateOlderPaging();
|
|
5006
5106
|
this.state = { ...this.state, nextBefore: null, loadingOlder: false };
|
|
5007
5107
|
this.cancelPatchFlush();
|
|
@@ -5036,7 +5136,6 @@ var AgentSession = class _AgentSession {
|
|
|
5036
5136
|
}
|
|
5037
5137
|
/** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
|
|
5038
5138
|
_rejoinAfterReconnect() {
|
|
5039
|
-
this.timelineEpoch += 1;
|
|
5040
5139
|
this.invalidateOlderPaging();
|
|
5041
5140
|
this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }));
|
|
5042
5141
|
const reconnectLiveRevision = this.liveRevision;
|
|
@@ -5054,7 +5153,7 @@ var AgentSession = class _AgentSession {
|
|
|
5054
5153
|
this.scheduleHistoricalCommandRestore(commandRecoveryGeneration);
|
|
5055
5154
|
}
|
|
5056
5155
|
await Promise.all([
|
|
5057
|
-
this.
|
|
5156
|
+
this.refreshAuthoritativeHistory({
|
|
5058
5157
|
liveRevisionAtStart: reconnectLiveRevision,
|
|
5059
5158
|
modeRevisionAtStart: reconnectModeRevision
|
|
5060
5159
|
}),
|
|
@@ -5216,7 +5315,7 @@ var AgentSession = class _AgentSession {
|
|
|
5216
5315
|
}
|
|
5217
5316
|
/** @internal */
|
|
5218
5317
|
_handleRewind(checkpointId) {
|
|
5219
|
-
this.
|
|
5318
|
+
this.invalidateTimeline();
|
|
5220
5319
|
this.invalidateOlderPaging();
|
|
5221
5320
|
this.update((s) => ({
|
|
5222
5321
|
...s,
|
|
@@ -5244,7 +5343,7 @@ var AgentSession = class _AgentSession {
|
|
|
5244
5343
|
message,
|
|
5245
5344
|
mode,
|
|
5246
5345
|
replay_decision: decision,
|
|
5247
|
-
kb_ids: kbIds
|
|
5346
|
+
kb_ids: kbIds
|
|
5248
5347
|
},
|
|
5249
5348
|
3e4
|
|
5250
5349
|
).then((response) => {
|
|
@@ -5314,7 +5413,7 @@ var AgentSession = class _AgentSession {
|
|
|
5314
5413
|
this.update((s) => ({ ...s, status: "running", isStreaming: true }));
|
|
5315
5414
|
} else if (this.state.isStreaming) {
|
|
5316
5415
|
this.update((s) => ({ ...s, isStreaming: false }));
|
|
5317
|
-
void this.
|
|
5416
|
+
void this.refreshAuthoritativeHistory({ liveRevisionAtStart: liveRevisionAtJoin });
|
|
5318
5417
|
}
|
|
5319
5418
|
}
|
|
5320
5419
|
// ---------------------------------------------------------------- 内部实现
|
|
@@ -5335,7 +5434,7 @@ var AgentSession = class _AgentSession {
|
|
|
5335
5434
|
completeChat(status) {
|
|
5336
5435
|
this.finishStreaming(status);
|
|
5337
5436
|
this.recentChatEndAt = Date.now();
|
|
5338
|
-
void this.
|
|
5437
|
+
void this.refreshAuthoritativeHistory();
|
|
5339
5438
|
this.emitter.emit("chatEnd", { status });
|
|
5340
5439
|
}
|
|
5341
5440
|
markTurnFresh(turnId) {
|
|
@@ -5519,8 +5618,32 @@ var AgentSession = class _AgentSession {
|
|
|
5519
5618
|
this.update((s) => addErrorMessage(s, OOM_MESSAGE));
|
|
5520
5619
|
this.emitter.emit("sandboxOom", { toolCallId: key });
|
|
5521
5620
|
}
|
|
5621
|
+
/**
|
|
5622
|
+
* 权威刷新(运行结束 / 重连补数):**按当前窗口第一条发言取窗口**,不再另记"用户想看哪段"。
|
|
5623
|
+
*
|
|
5624
|
+
* 窗口本身就是"用户在看哪段":首屏就是最新一页,向上翻页 / 定位之后首条就是用户滚到的位置。
|
|
5625
|
+
* 直接拿 `from_entry_id = 当前窗口第一条 turn_id` 去取,运行结束、重连补数、翻页之后的对账
|
|
5626
|
+
* 是同一条规则,不需要意图、锚点、已落地锚点这些状态;窗口首条已经不在分支上(404 / 409)时
|
|
5627
|
+
* 回落到最新一页。
|
|
5628
|
+
*/
|
|
5629
|
+
refreshAuthoritativeHistory(options = {}) {
|
|
5630
|
+
let entryGone = false;
|
|
5631
|
+
const locateTokenAtStart = this.locateToken;
|
|
5632
|
+
return this.replaceFromHistory({
|
|
5633
|
+
...options,
|
|
5634
|
+
// 锚点在**这次操作真正开始**时采样:排队期间用户可能刚定位过,那时窗口首条才是他要的。
|
|
5635
|
+
fromEntryId: () => this.state.turns[0]?.turn_id,
|
|
5636
|
+
onError: (error) => {
|
|
5637
|
+
entryGone = isEntryGoneError(error);
|
|
5638
|
+
}
|
|
5639
|
+
}).then((located) => {
|
|
5640
|
+
if (located || !entryGone) return located;
|
|
5641
|
+
if (this.locateToken !== locateTokenAtStart) return false;
|
|
5642
|
+
return this.replaceFromHistory(options);
|
|
5643
|
+
});
|
|
5644
|
+
}
|
|
5522
5645
|
replaceFromHistory(options = {}) {
|
|
5523
|
-
if (this.disposed) return Promise.resolve();
|
|
5646
|
+
if (this.disposed) return Promise.resolve(false);
|
|
5524
5647
|
const operationEpoch = this.timelineEpoch;
|
|
5525
5648
|
const liveRevisionAtStart = options.liveRevisionAtStart ?? this.liveRevision;
|
|
5526
5649
|
const modeRevisionAtStart = options.modeRevisionAtStart ?? this.modeRevision;
|
|
@@ -5528,13 +5651,35 @@ var AgentSession = class _AgentSession {
|
|
|
5528
5651
|
this.replaceInFlight += 1;
|
|
5529
5652
|
const operation = async () => {
|
|
5530
5653
|
let previousNextBefore = null;
|
|
5654
|
+
const restoreCursor = () => {
|
|
5655
|
+
if (this.disposed || previousNextBefore === null) return;
|
|
5656
|
+
this.update((state) => ({
|
|
5657
|
+
...state,
|
|
5658
|
+
nextBefore: previousNextBefore,
|
|
5659
|
+
loadingOlder: false
|
|
5660
|
+
}));
|
|
5661
|
+
};
|
|
5531
5662
|
try {
|
|
5532
|
-
if (this.disposed || operationEpoch !== this.timelineEpoch) return;
|
|
5663
|
+
if (this.disposed || operationEpoch !== this.timelineEpoch) return false;
|
|
5664
|
+
if (options.isStale?.()) return false;
|
|
5533
5665
|
this.invalidateOlderPaging();
|
|
5534
5666
|
previousNextBefore = this.state.nextBefore;
|
|
5535
5667
|
this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }));
|
|
5536
|
-
const
|
|
5537
|
-
|
|
5668
|
+
const signal = options.signal;
|
|
5669
|
+
const fromEntryId = typeof options.fromEntryId === "function" ? options.fromEntryId() : options.fromEntryId;
|
|
5670
|
+
const page = await this.runtime.fetchTurnsPage(
|
|
5671
|
+
this.sessionId,
|
|
5672
|
+
fromEntryId ? { fromEntryId } : void 0,
|
|
5673
|
+
signal ? { signal } : void 0
|
|
5674
|
+
);
|
|
5675
|
+
if (this.disposed || operationEpoch !== this.timelineEpoch) {
|
|
5676
|
+
restoreCursor();
|
|
5677
|
+
return false;
|
|
5678
|
+
}
|
|
5679
|
+
if (options.isStale?.()) {
|
|
5680
|
+
restoreCursor();
|
|
5681
|
+
return false;
|
|
5682
|
+
}
|
|
5538
5683
|
if (!this.joined) this.seedToolCallDeliveryBaseline(page.turns);
|
|
5539
5684
|
this.update((state) => {
|
|
5540
5685
|
const next = withTurns(
|
|
@@ -5553,7 +5698,9 @@ var AgentSession = class _AgentSession {
|
|
|
5553
5698
|
});
|
|
5554
5699
|
this.pruneOptimisticLiveRevisions();
|
|
5555
5700
|
this.projectionBuilder._seedTurns(this.state.turns);
|
|
5701
|
+
return true;
|
|
5556
5702
|
} catch (error) {
|
|
5703
|
+
options.onError?.(error);
|
|
5557
5704
|
if (!this.disposed && operationEpoch === this.timelineEpoch) {
|
|
5558
5705
|
this.update((state) => ({
|
|
5559
5706
|
...state,
|
|
@@ -5562,6 +5709,7 @@ var AgentSession = class _AgentSession {
|
|
|
5562
5709
|
}));
|
|
5563
5710
|
}
|
|
5564
5711
|
if (options.suppressErrors === false) throw error;
|
|
5712
|
+
return false;
|
|
5565
5713
|
} finally {
|
|
5566
5714
|
this.replaceInFlight -= 1;
|
|
5567
5715
|
}
|
|
@@ -5836,7 +5984,8 @@ var SessionHub = class {
|
|
|
5836
5984
|
});
|
|
5837
5985
|
}),
|
|
5838
5986
|
ensureConnected: () => this.ensureConnected(),
|
|
5839
|
-
fetchTurnsPage: (sessionId,
|
|
5987
|
+
fetchTurnsPage: (sessionId, query, init) => this.client.sessions.getSessionTurnsPage(sessionId, query, init),
|
|
5988
|
+
fetchTurnIndex: (sessionId) => this.client.sessions.getSessionTurnIndex(sessionId),
|
|
5840
5989
|
fetchCommands: (sessionId) => this.client.sessions.getSessionTurnCommands(sessionId),
|
|
5841
5990
|
fetchSessionInfo: (sessionId) => this.client.sessions.getSession(sessionId),
|
|
5842
5991
|
updateReplay: (sessionId, payload) => this.client.sessions.updateReplaySession(sessionId, payload).then((result) => result.replay_state ?? null),
|
|
@@ -6309,7 +6458,7 @@ var BladeClient = class {
|
|
|
6309
6458
|
signal: init.signal
|
|
6310
6459
|
});
|
|
6311
6460
|
if (response.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {
|
|
6312
|
-
const refreshed = await this.
|
|
6461
|
+
const refreshed = await this.tryRefreshUnlessAborted(init.signal);
|
|
6313
6462
|
if (refreshed) {
|
|
6314
6463
|
return this.fetch(method, path, init, true);
|
|
6315
6464
|
}
|
|
@@ -6363,6 +6512,27 @@ var BladeClient = class {
|
|
|
6363
6512
|
hasExplicitBearerToken() {
|
|
6364
6513
|
return Boolean(this.resolveRestToken());
|
|
6365
6514
|
}
|
|
6515
|
+
/**
|
|
6516
|
+
* 等一次令牌刷新,但调用方中止请求时不再等下去。
|
|
6517
|
+
*
|
|
6518
|
+
* 刷新本身是共享的(`refreshPromise`,别的请求也在等它),这里只是让这次已被取消的
|
|
6519
|
+
* 请求尽早结束——否则它会一直挂在调用方(定位)的串行队列里,用户改选的新目标要等到
|
|
6520
|
+
* 刷新结束才轮得到。
|
|
6521
|
+
*/
|
|
6522
|
+
async tryRefreshUnlessAborted(signal) {
|
|
6523
|
+
if (!signal) return this.tryRefresh();
|
|
6524
|
+
if (signal.aborted) throw new DOMException("The operation was aborted.", "AbortError");
|
|
6525
|
+
let onAbort;
|
|
6526
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
6527
|
+
onAbort = () => reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
6528
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
6529
|
+
});
|
|
6530
|
+
try {
|
|
6531
|
+
return await Promise.race([this.tryRefresh(), aborted]);
|
|
6532
|
+
} finally {
|
|
6533
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
6534
|
+
}
|
|
6535
|
+
}
|
|
6366
6536
|
async tryRefresh() {
|
|
6367
6537
|
if (this.refreshPromise) {
|
|
6368
6538
|
return this.refreshPromise;
|
|
@@ -6618,7 +6788,7 @@ function resolveServiceUrl(endpoints, name, path = "") {
|
|
|
6618
6788
|
|
|
6619
6789
|
// src/version.ts
|
|
6620
6790
|
var SDK_NAME = "agent-client";
|
|
6621
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
6791
|
+
var SDK_VERSION = true ? "2610.0.0-beta.71" : "1.1.1";
|
|
6622
6792
|
|
|
6623
6793
|
// src/commands/protocol.ts
|
|
6624
6794
|
function isCommandEnvelope(value) {
|
|
@@ -6771,8 +6941,10 @@ export {
|
|
|
6771
6941
|
groupAdjacentContextRuns,
|
|
6772
6942
|
groupMessagesByLoop,
|
|
6773
6943
|
hasChatRunEvent,
|
|
6944
|
+
inferToolStatus,
|
|
6774
6945
|
isAppDevToolUiCard,
|
|
6775
6946
|
isCommandEnvelope,
|
|
6947
|
+
isEntryGoneError,
|
|
6776
6948
|
isHiddenInternalMessage,
|
|
6777
6949
|
isInboundEnvelope,
|
|
6778
6950
|
isInternalStatusToolUiCard,
|