@blade-hq/agent-client 2610.0.0-beta.30 → 2610.0.0-beta.32
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 +3 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.js +131 -33
- package/dist/index.js.map +1 -1
- package/dist/schemas/context.d.ts +15 -0
- package/dist/schemas/message-utils.d.ts +3 -1
- package/dist/session/agent-session.d.ts +7 -1
- package/dist/session/events.d.ts +2 -0
- package/dist/session/hub.d.ts +8 -1
- package/package.json +1 -1
- package/public-api.md +30 -4
package/README.md
CHANGED
|
@@ -431,7 +431,7 @@ chat.on("chatEnd", (e) => console.log("回复结束", e.status))
|
|
|
431
431
|
chat.on("error", (e) => console.error(e.message))
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
-
完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`on()`
|
|
434
|
+
完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`toolResult.source` 区分实时结果、首次连接回放和断线重连回放;`on()` 返回取消函数,handler 抛异常只告警、不影响会话。
|
|
435
435
|
|
|
436
436
|
## iframe 嵌入形态:connectEmbedded
|
|
437
437
|
|
|
@@ -583,9 +583,9 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
583
583
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
584
584
|
- **会话资源(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`
|
|
585
585
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
586
|
-
- **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
586
|
+
- **会话状态机**:`SessionHub`、`SessionConnectOptions`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
587
587
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
588
|
-
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`ContextProjectionData`、`ContextProjectionFields`、`ContextDisplayState`、`ContextAction`、`ContextSourceInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`contextProjectionData`、`getContextDisplayState`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
588
|
+
- **消息与投影协议**:`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`
|
|
589
589
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
590
590
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
|
591
591
|
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { SDK_NAME, SDK_VERSION } from "./version";
|
|
|
8
8
|
export { AgentSession } from "./session/agent-session";
|
|
9
9
|
export type { AttachAppOptions, SendOptions } from "./session/agent-session";
|
|
10
10
|
export { SessionHub } from "./session/hub";
|
|
11
|
+
export type { SessionConnectOptions } from "./session/hub";
|
|
11
12
|
export type { AgentSessionEvents, AgentSessionEventName } from "./session/events";
|
|
12
13
|
export { SessionSetupError } from "./session/definition";
|
|
13
14
|
export type { SessionConfig, SessionDefinition, SessionSetupStage, SkillDefinition, TextFile, SolutionDefinition, } from "./session/definition";
|
|
@@ -29,8 +30,8 @@ export type { SessionsResource } from "./resources/sessions";
|
|
|
29
30
|
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
30
31
|
export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
|
|
31
32
|
export { buildMessageContent, chatErrorForDisplay, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
|
|
32
|
-
export { contextProjectionData, getContextDisplayState, } from "./schemas/context";
|
|
33
|
-
export type { ContextAction, ContextDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
|
|
33
|
+
export { contextProjectionData, getContextDisplayState, getContextGroupDisplayState, groupAdjacentContextRuns, } from "./schemas/context";
|
|
34
|
+
export type { ContextAction, ContextDisplayState, ContextGroupDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
|
|
34
35
|
export type { ParsedTextAttachment, ParsedTextContext, SkillMentionAvailability, } from "./schemas/message-utils";
|
|
35
36
|
export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PostChatFollowup, TurnProjection, } from "./schemas/projection";
|
|
36
37
|
export { latestPostChatFollowup } from "./schemas/projection-utils";
|
package/dist/index.js
CHANGED
|
@@ -1104,12 +1104,47 @@ function contextProjectionData(fields) {
|
|
|
1104
1104
|
};
|
|
1105
1105
|
}
|
|
1106
1106
|
function getContextDisplayState(context) {
|
|
1107
|
-
const title =
|
|
1107
|
+
const title = nonEmptyString(context.display_title) ?? BUILTIN_CONTEXT_TITLES[context.context_kind] ?? "\u5BF9\u8BDD\u80CC\u666F";
|
|
1108
1108
|
const isRemoved = context.context_action === "removed";
|
|
1109
1109
|
const summary = nonEmptyString(context.display_summary) ?? (isRemoved ? "\u5DF2\u505C\u6B62\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD" : context.context_action === "retained" ? "\u7EE7\u7EED\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD" : context.context_kind === "agent-instructions" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5BF9\u8BDD\u4F7F\u7528\u7684\u9879\u76EE\u8BF4\u660E" : context.context_kind === "skill-catalog" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u53EF\u7528\u80FD\u529B" : context.context_kind === "runtime-context" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5DE5\u4F5C\u73AF\u5883" : context.context_kind === "workspace-context" ? "\u5DF2\u66F4\u65B0\u672C\u6B21\u5DE5\u4F5C\u533A\u73AF\u5883" : "\u5DF2\u66F4\u65B0\u672C\u6B21\u5BF9\u8BDD\u80CC\u666F");
|
|
1110
1110
|
const detail = isRemoved ? `${title}\u5DF2\u4E0D\u518D\u7528\u4E8E\u540E\u7EED\u5BF9\u8BDD\u3002` : BUILTIN_CONTEXT_DETAILS[context.context_kind] ?? "\u8FD9\u4E9B\u4FE1\u606F\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u7406\u89E3\u5F53\u524D\u4EFB\u52A1\u3002";
|
|
1111
1111
|
return { title, summary, detail, isRemoved };
|
|
1112
1112
|
}
|
|
1113
|
+
function groupAdjacentContextRuns(kinds) {
|
|
1114
|
+
const runs = [];
|
|
1115
|
+
let current = null;
|
|
1116
|
+
kinds.forEach((kind, index) => {
|
|
1117
|
+
if (kind === null) {
|
|
1118
|
+
current = null;
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
if (current === null) {
|
|
1122
|
+
current = [];
|
|
1123
|
+
runs.push(current);
|
|
1124
|
+
}
|
|
1125
|
+
current.push(index);
|
|
1126
|
+
});
|
|
1127
|
+
return runs;
|
|
1128
|
+
}
|
|
1129
|
+
function getContextGroupDisplayState(contexts) {
|
|
1130
|
+
const count = contexts.length;
|
|
1131
|
+
if (count === 1) {
|
|
1132
|
+
const single = getContextDisplayState(contexts[0]);
|
|
1133
|
+
return { title: single.title, summary: single.summary, count };
|
|
1134
|
+
}
|
|
1135
|
+
const removed = contexts.filter(
|
|
1136
|
+
(context) => context.context_action === "removed"
|
|
1137
|
+
).length;
|
|
1138
|
+
const updated = count - removed;
|
|
1139
|
+
const parts = [];
|
|
1140
|
+
if (updated > 0) parts.push(`${updated} \u9879\u5DF2\u66F4\u65B0`);
|
|
1141
|
+
if (removed > 0) parts.push(`${removed} \u9879\u5DF2\u505C\u7528`);
|
|
1142
|
+
return {
|
|
1143
|
+
title: "\u5BF9\u8BDD\u80CC\u666F",
|
|
1144
|
+
summary: parts.join(" \xB7 ") || `${count} \u9879`,
|
|
1145
|
+
count
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1113
1148
|
|
|
1114
1149
|
// src/shared/projection/context.ts
|
|
1115
1150
|
function isRecord2(value) {
|
|
@@ -2015,7 +2050,11 @@ function projectHistory(entries) {
|
|
|
2015
2050
|
model: stringOrNull(message.model),
|
|
2016
2051
|
usage: isRecord4(message._usage) ? { ...message._usage } : null,
|
|
2017
2052
|
duration_ms: numberOrZero(message._duration_ms),
|
|
2018
|
-
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
|
|
2053
|
+
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0,
|
|
2054
|
+
// fork 子会话的父锚点:历史里落在消息级 _parent_fork_tool_call_id。丢掉它,
|
|
2055
|
+
// 刷新后工作流步骤 fork 就配不回 workflow:run 工具调用(普通 Agent fork 有
|
|
2056
|
+
// root Agent 工具调用兜底配对,工作流 fork 没有,子智能体卡会整体消失)。
|
|
2057
|
+
parent_fork_tool_call_id: stringOrNull(message._parent_fork_tool_call_id)
|
|
2019
2058
|
};
|
|
2020
2059
|
const isNativeToolEntry = role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.some(
|
|
2021
2060
|
(toolCall) => isRecord4(toolCall) && typeof toolCall.provider === "string"
|
|
@@ -2990,10 +3029,10 @@ function isLegacyForkContextText(text) {
|
|
|
2990
3029
|
const normalized = text.trim();
|
|
2991
3030
|
return LEGACY_FORK_CONTEXT_MARKERS.every((marker) => normalized.includes(marker));
|
|
2992
3031
|
}
|
|
2993
|
-
function isHiddenInternalMessage(message) {
|
|
3032
|
+
function isHiddenInternalMessage(message, options = {}) {
|
|
2994
3033
|
if (message.role !== "user") return false;
|
|
2995
3034
|
const text = getTextContent(normalizeMessageContent(message.content));
|
|
2996
|
-
return isSystemReminderText(text) || isSystemNotificationText(text) || isLegacyForkContextText(text);
|
|
3035
|
+
return isSystemReminderText(text) || isSystemNotificationText(text) || (options.includeLegacyForkContext ?? true) && isLegacyForkContextText(text);
|
|
2997
3036
|
}
|
|
2998
3037
|
function buildMessageContent(text, attachments) {
|
|
2999
3038
|
if (attachments.length === 0) return text;
|
|
@@ -3673,6 +3712,10 @@ var AgentSession = class _AgentSession {
|
|
|
3673
3712
|
patchFlushCancel = null;
|
|
3674
3713
|
joined = false;
|
|
3675
3714
|
joinPending = null;
|
|
3715
|
+
// bootstrap 与每次 reconnect 共用一条订阅生命周期队列。它们都会重置 join
|
|
3716
|
+
// 状态并临时设置 replay source,禁止并发,否则较早操作的 finally 会清掉
|
|
3717
|
+
// 较晚操作仍在使用的来源上下文。
|
|
3718
|
+
subscriptionQueue = Promise.resolve();
|
|
3676
3719
|
// 回放控制请求排成一条队列。连着点"5x"再点"退出回放"时,并发发出去的两个
|
|
3677
3720
|
// 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用
|
|
3678
3721
|
// 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个
|
|
@@ -3682,6 +3725,7 @@ var AgentSession = class _AgentSession {
|
|
|
3682
3725
|
pendingReplayMode;
|
|
3683
3726
|
pendingReplayKbIds;
|
|
3684
3727
|
recentChatEndAt = 0;
|
|
3728
|
+
subscriptionReplaySource = null;
|
|
3685
3729
|
disposed = false;
|
|
3686
3730
|
getAppContext = null;
|
|
3687
3731
|
sendPending = false;
|
|
@@ -3999,27 +4043,47 @@ var AgentSession = class _AgentSession {
|
|
|
3999
4043
|
this.update((s) => ({ ...s, connection }));
|
|
4000
4044
|
}
|
|
4001
4045
|
/** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */
|
|
4002
|
-
|
|
4046
|
+
_rejoinAfterReconnect() {
|
|
4003
4047
|
const turnsBeforeRejoin = this.state.turns;
|
|
4004
|
-
this.
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4048
|
+
return this.enqueueSubscription(async () => {
|
|
4049
|
+
this.joined = false;
|
|
4050
|
+
this.joinPending = null;
|
|
4051
|
+
try {
|
|
4052
|
+
this.subscriptionReplaySource = "reconnect_replay";
|
|
4053
|
+
try {
|
|
4054
|
+
await this.ensureJoined();
|
|
4055
|
+
} finally {
|
|
4056
|
+
this.subscriptionReplaySource = null;
|
|
4057
|
+
}
|
|
4058
|
+
await Promise.all([
|
|
4059
|
+
this.syncTurnsFromHistory({
|
|
4060
|
+
clearOnEmpty: true,
|
|
4061
|
+
preserveChangesSince: turnsBeforeRejoin
|
|
4062
|
+
}),
|
|
4063
|
+
this.syncReplayFromSession()
|
|
4064
|
+
]);
|
|
4065
|
+
} catch {
|
|
4066
|
+
}
|
|
4067
|
+
});
|
|
4017
4068
|
}
|
|
4018
4069
|
/** @internal 首次连接:加载历史 + 加入房间。 */
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4070
|
+
_bootstrap() {
|
|
4071
|
+
return this.enqueueSubscription(async () => {
|
|
4072
|
+
await this.syncTurnsFromHistory({ suppressErrors: false });
|
|
4073
|
+
this.subscriptionReplaySource = "bootstrap_replay";
|
|
4074
|
+
try {
|
|
4075
|
+
await this.ensureJoined();
|
|
4076
|
+
} finally {
|
|
4077
|
+
this.subscriptionReplaySource = null;
|
|
4078
|
+
}
|
|
4079
|
+
await this.syncReplayFromSession();
|
|
4080
|
+
});
|
|
4081
|
+
}
|
|
4082
|
+
/** 订阅生命周期串行执行;一次失败只由自己的调用方观察,不截断后续重连。 */
|
|
4083
|
+
enqueueSubscription(operation) {
|
|
4084
|
+
const run = this.subscriptionQueue.then(operation);
|
|
4085
|
+
this.subscriptionQueue = run.catch(() => void 0);
|
|
4086
|
+
return run;
|
|
4023
4087
|
}
|
|
4024
4088
|
/** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */
|
|
4025
4089
|
get canControlReplay() {
|
|
@@ -4076,7 +4140,7 @@ var AgentSession = class _AgentSession {
|
|
|
4076
4140
|
this.applyTurn(turn);
|
|
4077
4141
|
}
|
|
4078
4142
|
/** @internal 历史回放通道(event_format: raw)。 */
|
|
4079
|
-
_handleTurnEvents(events) {
|
|
4143
|
+
_handleTurnEvents(events, replayed = false) {
|
|
4080
4144
|
if (!events.length) return;
|
|
4081
4145
|
const terminalChatEndStatus = extractTerminalChatEndStatus(events);
|
|
4082
4146
|
if (!terminalChatEndStatus && hasChatRunEvent2(events) && this.state.status !== "waiting_for_input") {
|
|
@@ -4088,7 +4152,10 @@ var AgentSession = class _AgentSession {
|
|
|
4088
4152
|
const updates = this.projectionBuilder.processBatch(events);
|
|
4089
4153
|
for (const update of updates) {
|
|
4090
4154
|
if (update.kind === "upsert") {
|
|
4091
|
-
this.applyTurn(
|
|
4155
|
+
this.applyTurn(
|
|
4156
|
+
update.turn,
|
|
4157
|
+
replayed ? this.subscriptionReplaySource ?? "bootstrap_replay" : "live"
|
|
4158
|
+
);
|
|
4092
4159
|
} else if (update.kind === "workspace_changed") {
|
|
4093
4160
|
this.emitter.emit("workspaceChanged", {});
|
|
4094
4161
|
}
|
|
@@ -4257,11 +4324,11 @@ var AgentSession = class _AgentSession {
|
|
|
4257
4324
|
void this.syncTurnsFromHistory();
|
|
4258
4325
|
this.emitter.emit("chatEnd", { status });
|
|
4259
4326
|
}
|
|
4260
|
-
applyTurn(turn) {
|
|
4327
|
+
applyTurn(turn, source = "live") {
|
|
4261
4328
|
this.flushPatches();
|
|
4262
4329
|
const previous = this.state;
|
|
4263
4330
|
this.update((s) => upsertTurn(s, turn));
|
|
4264
|
-
this.emitTurnDerivedEvents(previous, turn);
|
|
4331
|
+
this.emitTurnDerivedEvents(previous, turn, source);
|
|
4265
4332
|
}
|
|
4266
4333
|
schedulePatchFlush() {
|
|
4267
4334
|
if (this.patchFlushHandle != null) return;
|
|
@@ -4307,7 +4374,7 @@ var AgentSession = class _AgentSession {
|
|
|
4307
4374
|
}
|
|
4308
4375
|
}
|
|
4309
4376
|
/** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */
|
|
4310
|
-
emitTurnDerivedEvents(previous, turn) {
|
|
4377
|
+
emitTurnDerivedEvents(previous, turn, source = "live") {
|
|
4311
4378
|
const mode = extractModeFromBlocks(turn.blocks);
|
|
4312
4379
|
if (mode && previous.mode !== mode) {
|
|
4313
4380
|
this.emitter.emit("modeChange", { mode });
|
|
@@ -4356,7 +4423,7 @@ var AgentSession = class _AgentSession {
|
|
|
4356
4423
|
const finished = toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled";
|
|
4357
4424
|
if (finished && !this.finishedToolCallIds.has(toolCall.id)) {
|
|
4358
4425
|
this.finishedToolCallIds.add(toolCall.id);
|
|
4359
|
-
this.emitter.emit("toolResult", { toolCall: info, turn });
|
|
4426
|
+
this.emitter.emit("toolResult", { toolCall: info, turn, source });
|
|
4360
4427
|
if (isOomResult(toolCall.result)) {
|
|
4361
4428
|
this.notifySandboxOom(toolCall.id);
|
|
4362
4429
|
}
|
|
@@ -4398,6 +4465,7 @@ var AgentSession = class _AgentSession {
|
|
|
4398
4465
|
try {
|
|
4399
4466
|
const turns = await this.runtime.fetchTurns(this.sessionId);
|
|
4400
4467
|
if (turns.length === 0 && !clearOnEmpty) return;
|
|
4468
|
+
if (!this.joined) this.seedToolCallDeliveryBaseline(turns);
|
|
4401
4469
|
this.update((state) => {
|
|
4402
4470
|
const mergeBaseline = preserveChangesSince ?? turnsAtRequestStart;
|
|
4403
4471
|
if (state.turns === mergeBaseline) return withTurns(state, turns);
|
|
@@ -4416,6 +4484,17 @@ var AgentSession = class _AgentSession {
|
|
|
4416
4484
|
if (!suppressErrors) throw error;
|
|
4417
4485
|
}
|
|
4418
4486
|
}
|
|
4487
|
+
/** 首次订阅前的 REST 历史建立语义事件基线,随后同一工具的订阅回放不再投递。 */
|
|
4488
|
+
seedToolCallDeliveryBaseline(turns) {
|
|
4489
|
+
for (const turn of turns) {
|
|
4490
|
+
for (const toolCall of turn.tool_calls) {
|
|
4491
|
+
this.seenToolCallIds.add(toolCall.id);
|
|
4492
|
+
if (toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled") {
|
|
4493
|
+
this.finishedToolCallIds.add(toolCall.id);
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4419
4498
|
/**
|
|
4420
4499
|
* 把历史里的指令补投给宿主页面。
|
|
4421
4500
|
*
|
|
@@ -4515,16 +4594,28 @@ var SessionHub = class {
|
|
|
4515
4594
|
* 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类"连两次
|
|
4516
4595
|
* 只释放一次"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。
|
|
4517
4596
|
*/
|
|
4518
|
-
async connect(sessionId) {
|
|
4597
|
+
async connect(sessionId, options = {}) {
|
|
4519
4598
|
const existing = this.sessions.get(sessionId);
|
|
4520
4599
|
if (existing && !existing.isDisposed) {
|
|
4521
4600
|
this.hold(sessionId);
|
|
4601
|
+
try {
|
|
4602
|
+
options.setup?.(existing);
|
|
4603
|
+
} catch (error) {
|
|
4604
|
+
existing.dispose();
|
|
4605
|
+
throw error;
|
|
4606
|
+
}
|
|
4522
4607
|
return this.bootstrapPending.get(sessionId) ?? existing;
|
|
4523
4608
|
}
|
|
4524
4609
|
this.ensureBound();
|
|
4525
4610
|
const session = new AgentSession(sessionId, this.runtimeFor(), this.connection);
|
|
4526
4611
|
this.sessions.set(sessionId, session);
|
|
4527
4612
|
this.hold(sessionId);
|
|
4613
|
+
try {
|
|
4614
|
+
options.setup?.(session);
|
|
4615
|
+
} catch (error) {
|
|
4616
|
+
session.dispose();
|
|
4617
|
+
throw error;
|
|
4618
|
+
}
|
|
4528
4619
|
this.ensureConnected();
|
|
4529
4620
|
const bootstrap = session._bootstrap().then(() => session);
|
|
4530
4621
|
this.bootstrapPending.set(sessionId, bootstrap);
|
|
@@ -4686,9 +4777,14 @@ var SessionHub = class {
|
|
|
4686
4777
|
socket.on("turn:end", (data) => {
|
|
4687
4778
|
for (const session of this.route(data.session_id)) session._handleTurnEnd(data);
|
|
4688
4779
|
});
|
|
4689
|
-
socket.on(
|
|
4690
|
-
|
|
4691
|
-
|
|
4780
|
+
socket.on(
|
|
4781
|
+
"turn:events",
|
|
4782
|
+
(data) => {
|
|
4783
|
+
for (const session of this.route(data.session_id)) {
|
|
4784
|
+
session._handleTurnEvents(data.events ?? [], data.replayed === true);
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
);
|
|
4692
4788
|
socket.on("chat:start", (data) => {
|
|
4693
4789
|
for (const session of this.route(data?.session_id)) session._handleChatStart();
|
|
4694
4790
|
});
|
|
@@ -4818,7 +4914,7 @@ function resolveAuthToken(options) {
|
|
|
4818
4914
|
|
|
4819
4915
|
// src/version.ts
|
|
4820
4916
|
var SDK_NAME = "agent-client";
|
|
4821
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4917
|
+
var SDK_VERSION = true ? "2610.0.0-beta.32" : "1.1.1";
|
|
4822
4918
|
|
|
4823
4919
|
// src/socket.ts
|
|
4824
4920
|
function withSdkIdentity(auth) {
|
|
@@ -5424,9 +5520,11 @@ export {
|
|
|
5424
5520
|
createSocket,
|
|
5425
5521
|
extractTextAttachments,
|
|
5426
5522
|
getContextDisplayState,
|
|
5523
|
+
getContextGroupDisplayState,
|
|
5427
5524
|
getFileParts,
|
|
5428
5525
|
getImageParts,
|
|
5429
5526
|
getTextContent,
|
|
5527
|
+
groupAdjacentContextRuns,
|
|
5430
5528
|
groupMessagesByLoop,
|
|
5431
5529
|
isCommandEnvelope,
|
|
5432
5530
|
isHiddenInternalMessage,
|