@blade-hq/agent-client 2610.0.0-beta.16 → 2610.0.0-beta.18
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 +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +190 -38
- package/dist/index.js.map +1 -1
- package/dist/schemas/context.d.ts +34 -0
- package/dist/schemas/message.d.ts +3 -0
- package/dist/schemas/projection.d.ts +10 -1
- package/dist/session/state.d.ts +3 -1
- package/dist/shared/projection/builder.d.ts +1 -0
- package/dist/shared/projection/context.d.ts +3 -0
- package/dist/shared/projection/history.d.ts +1 -0
- package/dist/shared/projection/index.d.ts +1 -0
- package/package.json +1 -1
- package/public-api.md +74 -2
package/README.md
CHANGED
|
@@ -542,7 +542,7 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
|
|
|
542
542
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
|
543
543
|
- **会话状态机**:`SessionHub`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
|
|
544
544
|
- **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
|
|
545
|
-
- **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
|
|
545
|
+
- **消息与投影协议**:`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`
|
|
546
546
|
- **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
|
|
547
547
|
- **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
|
|
548
548
|
- **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`ClientProjectionBuilder`、`RawEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export type { SessionsResource } from "./resources/sessions";
|
|
|
26
26
|
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, SessionContextStats, SessionHistory, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
|
27
27
|
export type { ArchivedFileInfo, ArchivedToolCallInfo, ChatMessage, CompactionInfo, FileContentPart, ImageUrlContentPart, MemoryRefInfo, MessageContent, MessageContentPart, TextContentPart, ToolBridgeContent, ToolCallInfo, } from "./schemas/message";
|
|
28
28
|
export { buildMessageContent, contentPreview, extractTextAttachments, getFileParts, getImageParts, getTextContent, groupMessagesByLoop, isHiddenInternalMessage, normalizeMessageContent, transformSlashCommand, } from "./schemas/message-utils";
|
|
29
|
+
export { contextProjectionData, getContextDisplayState, } from "./schemas/context";
|
|
30
|
+
export type { ContextAction, ContextDisplayState, ContextProjectionData, ContextProjectionFields, ContextSourceInfo, } from "./schemas/context";
|
|
29
31
|
export type { ParsedTextAttachment, ParsedTextContext, SkillMentionAvailability, } from "./schemas/message-utils";
|
|
30
32
|
export type { ContentBlock, FinalArtifact, MemoryRef, PatchEnvelope, PostChatFollowup, TurnProjection, } from "./schemas/projection";
|
|
31
33
|
export { latestPostChatFollowup } from "./schemas/projection-utils";
|
package/dist/index.js
CHANGED
|
@@ -1023,6 +1023,87 @@ function toolStatusFromResult(result) {
|
|
|
1023
1023
|
return inferToolStatus(text);
|
|
1024
1024
|
}
|
|
1025
1025
|
|
|
1026
|
+
// src/schemas/context.ts
|
|
1027
|
+
var BUILTIN_CONTEXT_TITLES = {
|
|
1028
|
+
"agent-instructions": "\u9879\u76EE\u8BF4\u660E",
|
|
1029
|
+
"skill-catalog": "\u53EF\u7528\u80FD\u529B",
|
|
1030
|
+
"runtime-context": "\u5F53\u524D\u5DE5\u4F5C\u73AF\u5883"
|
|
1031
|
+
};
|
|
1032
|
+
var BUILTIN_CONTEXT_DETAILS = {
|
|
1033
|
+
"agent-instructions": "\u8FD9\u4E9B\u8BF4\u660E\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u7406\u89E3\u5F53\u524D\u9879\u76EE\u548C\u5DE5\u4F5C\u8981\u6C42\u3002",
|
|
1034
|
+
"skill-catalog": "\u8FD9\u4E9B\u80FD\u529B\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u9009\u62E9\u5408\u9002\u7684\u65B9\u5F0F\u5B8C\u6210\u4EFB\u52A1\u3002",
|
|
1035
|
+
"runtime-context": "\u8FD9\u4E9B\u4FE1\u606F\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u4E86\u89E3\u5F53\u524D\u6587\u4EF6\u5939\u548C\u8FD0\u884C\u6761\u4EF6\u3002"
|
|
1036
|
+
};
|
|
1037
|
+
function nonEmptyString(value) {
|
|
1038
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1039
|
+
}
|
|
1040
|
+
function contextProjectionData(fields) {
|
|
1041
|
+
const contextKind = nonEmptyString(fields.context_kind);
|
|
1042
|
+
const contextKey = nonEmptyString(fields.context_key);
|
|
1043
|
+
const contextName = nonEmptyString(fields.context_name);
|
|
1044
|
+
const contextRevision = nonEmptyString(fields.context_revision);
|
|
1045
|
+
if (!contextKind || !contextKey || !contextName || !contextRevision || typeof fields.context_order !== "number" || !Number.isFinite(fields.context_order) || !fields.context_action) {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
return {
|
|
1049
|
+
context_kind: contextKind,
|
|
1050
|
+
context_key: contextKey,
|
|
1051
|
+
context_name: contextName,
|
|
1052
|
+
context_order: fields.context_order,
|
|
1053
|
+
context_action: fields.context_action,
|
|
1054
|
+
context_revision: contextRevision,
|
|
1055
|
+
display_title: nonEmptyString(fields.display_title),
|
|
1056
|
+
display_summary: nonEmptyString(fields.display_summary),
|
|
1057
|
+
sources: Array.isArray(fields.sources) ? fields.sources : []
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
function getContextDisplayState(context) {
|
|
1061
|
+
const title = BUILTIN_CONTEXT_TITLES[context.context_kind] ?? nonEmptyString(context.display_title) ?? "\u5BF9\u8BDD\u80CC\u666F";
|
|
1062
|
+
const isRemoved = context.context_action === "removed";
|
|
1063
|
+
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" : "\u5DF2\u66F4\u65B0\u672C\u6B21\u5BF9\u8BDD\u80CC\u666F");
|
|
1064
|
+
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";
|
|
1065
|
+
return { title, summary, detail, isRemoved };
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// src/shared/projection/context.ts
|
|
1069
|
+
function isRecord2(value) {
|
|
1070
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1071
|
+
}
|
|
1072
|
+
function buildContextTurn(entry, sequence) {
|
|
1073
|
+
if (entry.kind !== "context" || !isRecord2(entry.source) || !isRecord2(entry.data)) {
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
const display = isRecord2(entry.data.display) ? entry.data.display : {};
|
|
1077
|
+
const context = contextProjectionData({
|
|
1078
|
+
context_kind: typeof entry.source.kind === "string" ? entry.source.kind : null,
|
|
1079
|
+
context_key: typeof entry.source.key === "string" ? entry.source.key : null,
|
|
1080
|
+
context_name: typeof entry.data.contribution_name === "string" ? entry.data.contribution_name : null,
|
|
1081
|
+
context_order: typeof entry.data.order === "number" ? entry.data.order : null,
|
|
1082
|
+
context_action: entry.data.action === "published" || entry.data.action === "retained" || entry.data.action === "removed" ? entry.data.action : null,
|
|
1083
|
+
context_revision: typeof entry.data.revision === "string" ? entry.data.revision : null,
|
|
1084
|
+
display_title: typeof display.title === "string" ? display.title : null,
|
|
1085
|
+
display_summary: typeof display.summary === "string" ? display.summary : null,
|
|
1086
|
+
sources: Array.isArray(display.sources) ? display.sources.filter(isRecord2) : []
|
|
1087
|
+
});
|
|
1088
|
+
if (!context) return null;
|
|
1089
|
+
const turnId = typeof entry.id === "string" && entry.id ? entry.id : `context-${sequence}`;
|
|
1090
|
+
return {
|
|
1091
|
+
id: turnId,
|
|
1092
|
+
sequence,
|
|
1093
|
+
turn_id: turnId,
|
|
1094
|
+
loop_id: typeof entry.loop_name === "string" && entry.loop_name ? entry.loop_name : "root",
|
|
1095
|
+
kind: "context",
|
|
1096
|
+
role: "system",
|
|
1097
|
+
status: "completed",
|
|
1098
|
+
blocks: [],
|
|
1099
|
+
tool_calls: [],
|
|
1100
|
+
model: null,
|
|
1101
|
+
usage: null,
|
|
1102
|
+
duration_ms: 0,
|
|
1103
|
+
...context
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1026
1107
|
// src/shared/projection/builder.ts
|
|
1027
1108
|
function hasChatRunEvent(events) {
|
|
1028
1109
|
return events.some(
|
|
@@ -1117,6 +1198,8 @@ var ClientProjectionBuilder = class {
|
|
|
1117
1198
|
return this.onMemoryInject(loopId, payload);
|
|
1118
1199
|
case "memory:inject:none":
|
|
1119
1200
|
return null;
|
|
1201
|
+
case "context:entry":
|
|
1202
|
+
return this.onContextEntry(payload);
|
|
1120
1203
|
case "loop:turn":
|
|
1121
1204
|
return this.onLoopTurn(loopId, payload);
|
|
1122
1205
|
case "mode:change":
|
|
@@ -1232,6 +1315,11 @@ var ClientProjectionBuilder = class {
|
|
|
1232
1315
|
}
|
|
1233
1316
|
return null;
|
|
1234
1317
|
}
|
|
1318
|
+
onContextEntry(payload) {
|
|
1319
|
+
if (!isRecord3(payload.entry)) return null;
|
|
1320
|
+
const turn = buildContextTurn(payload.entry, this.nextSeq());
|
|
1321
|
+
return turn ? [{ kind: "upsert", turn }] : null;
|
|
1322
|
+
}
|
|
1235
1323
|
onLoopTurn(loopId, payload) {
|
|
1236
1324
|
let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`));
|
|
1237
1325
|
let memoryRefs = null;
|
|
@@ -1288,11 +1376,11 @@ var ClientProjectionBuilder = class {
|
|
|
1288
1376
|
loopId,
|
|
1289
1377
|
toolCallId: optStr(payload.tool_call_id) ?? void 0,
|
|
1290
1378
|
toolName: toolNameFromPayload(payload) ?? void 0,
|
|
1291
|
-
workspacePath:
|
|
1379
|
+
workspacePath: isRecord3(payload.workspace_change) ? optStr(payload.workspace_change.to) ?? void 0 : void 0
|
|
1292
1380
|
}
|
|
1293
1381
|
];
|
|
1294
1382
|
const change = payload.workspace_change;
|
|
1295
|
-
if (
|
|
1383
|
+
if (isRecord3(change)) {
|
|
1296
1384
|
const source = optStr(change.source) ?? "";
|
|
1297
1385
|
const projectName = optStr(change.project_name) ?? "";
|
|
1298
1386
|
const fromPath = optStr(change.from) ?? "";
|
|
@@ -1754,7 +1842,7 @@ var ClientProjectionBuilder = class {
|
|
|
1754
1842
|
return `${prefix}:${this.syntheticCounter}:${hex}`;
|
|
1755
1843
|
}
|
|
1756
1844
|
};
|
|
1757
|
-
function
|
|
1845
|
+
function isRecord3(value) {
|
|
1758
1846
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1759
1847
|
}
|
|
1760
1848
|
function optStr(value) {
|
|
@@ -1790,7 +1878,7 @@ function projectHistory(entries) {
|
|
|
1790
1878
|
const kind = String(entry.kind ?? "");
|
|
1791
1879
|
const loopId = String(entry.loop_name ?? "root");
|
|
1792
1880
|
const id = String(entry.id ?? `history-${sequence + 1}`);
|
|
1793
|
-
if (kind === "post_chat_followup" &&
|
|
1881
|
+
if (kind === "post_chat_followup" && isRecord4(entry.data)) {
|
|
1794
1882
|
const assistantEntryId = String(entry.data.assistant_entry_id ?? "");
|
|
1795
1883
|
if (latestRootMessage?.role === "assistant" && latestRootMessage.turn_id === assistantEntryId) {
|
|
1796
1884
|
const followup = normalizePostChatFollowup(entry.data, assistantEntryId);
|
|
@@ -1798,7 +1886,15 @@ function projectHistory(entries) {
|
|
|
1798
1886
|
}
|
|
1799
1887
|
continue;
|
|
1800
1888
|
}
|
|
1801
|
-
if (kind === "
|
|
1889
|
+
if (kind === "context") {
|
|
1890
|
+
const turn = buildContextTurn(entry, sequence + 1);
|
|
1891
|
+
if (turn) {
|
|
1892
|
+
sequence += 1;
|
|
1893
|
+
turns.push(turn);
|
|
1894
|
+
}
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1897
|
+
if (kind === "message" && isRecord4(entry.message)) {
|
|
1802
1898
|
const message = entry.message;
|
|
1803
1899
|
const role = String(message.role ?? "");
|
|
1804
1900
|
if (role === "tool") {
|
|
@@ -1830,7 +1926,7 @@ function projectHistory(entries) {
|
|
|
1830
1926
|
blocks,
|
|
1831
1927
|
tool_calls: toolCalls,
|
|
1832
1928
|
model: stringOrNull(message.model),
|
|
1833
|
-
usage:
|
|
1929
|
+
usage: isRecord4(message._usage) ? { ...message._usage } : null,
|
|
1834
1930
|
duration_ms: numberOrZero(message._duration_ms),
|
|
1835
1931
|
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
|
|
1836
1932
|
};
|
|
@@ -1849,7 +1945,7 @@ function projectHistory(entries) {
|
|
|
1849
1945
|
if (kind === "mode_change") {
|
|
1850
1946
|
turns.push(markerTurn(id, ++sequence, loopId, "mode_change", entry.data ?? {}));
|
|
1851
1947
|
} else if (kind === "workspace_change") {
|
|
1852
|
-
const change =
|
|
1948
|
+
const change = isRecord4(entry.data) ? entry.data : {};
|
|
1853
1949
|
const source = stringOrNull(change.source) ?? "";
|
|
1854
1950
|
const projectName = stringOrNull(change.project_name) ?? "";
|
|
1855
1951
|
const fromPath = stringOrNull(change.from) ?? "";
|
|
@@ -1890,7 +1986,7 @@ function projectHistory(entries) {
|
|
|
1890
1986
|
} else if (kind === "compaction" || kind === "tool_result_archive") {
|
|
1891
1987
|
const data = entry.data ?? {};
|
|
1892
1988
|
const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`);
|
|
1893
|
-
let content =
|
|
1989
|
+
let content = isRecord4(entry.message) ? entry.message.content : void 0;
|
|
1894
1990
|
if (kind === "tool_result_archive") {
|
|
1895
1991
|
const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0;
|
|
1896
1992
|
content = `<compaction-summary>
|
|
@@ -1905,11 +2001,11 @@ function projectHistory(entries) {
|
|
|
1905
2001
|
);
|
|
1906
2002
|
} else if (kind === "child_pause") {
|
|
1907
2003
|
const data = entry.data ?? {};
|
|
1908
|
-
const sourceLoop =
|
|
2004
|
+
const sourceLoop = isRecord4(data.source_loop) ? data.source_loop : {};
|
|
1909
2005
|
const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? "");
|
|
1910
2006
|
const childToolCallId = String(data.child_pause_tool_call_id ?? "");
|
|
1911
2007
|
const parentToolCallId = String(data.parent_fork_tool_call_id ?? "");
|
|
1912
|
-
const pauseToolData =
|
|
2008
|
+
const pauseToolData = isRecord4(data.pause_tool_data) ? data.pause_tool_data : {};
|
|
1913
2009
|
const description = String(sourceLoop.description ?? "");
|
|
1914
2010
|
applyAskUserPauseToTurn(
|
|
1915
2011
|
latestAssistantByLoop.get(childLoopId),
|
|
@@ -1997,15 +2093,15 @@ function parseToolArguments(value) {
|
|
|
1997
2093
|
if (!value) return {};
|
|
1998
2094
|
try {
|
|
1999
2095
|
const parsed = JSON.parse(value);
|
|
2000
|
-
return
|
|
2096
|
+
return isRecord4(parsed) ? parsed : {};
|
|
2001
2097
|
} catch {
|
|
2002
2098
|
return {};
|
|
2003
2099
|
}
|
|
2004
2100
|
}
|
|
2005
2101
|
function buildToolCalls(value) {
|
|
2006
2102
|
if (!Array.isArray(value)) return [];
|
|
2007
|
-
return value.filter(
|
|
2008
|
-
const fn =
|
|
2103
|
+
return value.filter(isRecord4).map((raw) => {
|
|
2104
|
+
const fn = isRecord4(raw.function) ? raw.function : {};
|
|
2009
2105
|
const name = String(fn.name ?? "");
|
|
2010
2106
|
return {
|
|
2011
2107
|
id: String(raw.id ?? ""),
|
|
@@ -2025,7 +2121,7 @@ function buildBlocks(message, toolCalls) {
|
|
|
2025
2121
|
blocks.push({ type: "text", content: displayContent });
|
|
2026
2122
|
} else if (Array.isArray(stored)) {
|
|
2027
2123
|
for (const raw of stored) {
|
|
2028
|
-
if (!
|
|
2124
|
+
if (!isRecord4(raw)) continue;
|
|
2029
2125
|
const type3 = String(raw.type ?? "");
|
|
2030
2126
|
if (type3 === "thinking") blocks.push({ type: type3, content: raw.thinking ?? raw.content ?? "" });
|
|
2031
2127
|
if (type3 === "text") blocks.push({ type: type3, content: raw.text ?? raw.content ?? "" });
|
|
@@ -2058,7 +2154,7 @@ function markerTurn(id, sequence, loopId, type3, content, toolCallId = null) {
|
|
|
2058
2154
|
duration_ms: 0
|
|
2059
2155
|
};
|
|
2060
2156
|
}
|
|
2061
|
-
function
|
|
2157
|
+
function isRecord4(value) {
|
|
2062
2158
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2063
2159
|
}
|
|
2064
2160
|
function stringOrNull(value) {
|
|
@@ -2903,10 +2999,10 @@ function inferLoopStatusFromMessages(messages) {
|
|
|
2903
2999
|
}
|
|
2904
3000
|
function inferLoopStatusFromTurns(turns, messages) {
|
|
2905
3001
|
const latestAgentNotification = [...turns].reverse().flatMap((turn) => turn.blocks).find((block) => {
|
|
2906
|
-
if (block.type !== "system_notification" || !
|
|
3002
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) return false;
|
|
2907
3003
|
return block.content.notification_type === "agent:start" || block.content.notification_type === "agent:end";
|
|
2908
3004
|
});
|
|
2909
|
-
if (latestAgentNotification?.type === "system_notification" &&
|
|
3005
|
+
if (latestAgentNotification?.type === "system_notification" && isRecord5(latestAgentNotification.content)) {
|
|
2910
3006
|
const notificationType = latestAgentNotification.content.notification_type;
|
|
2911
3007
|
const status = latestAgentNotification.content.status;
|
|
2912
3008
|
if (notificationType === "agent:start" || status === "running") return "running";
|
|
@@ -2915,17 +3011,47 @@ function inferLoopStatusFromTurns(turns, messages) {
|
|
|
2915
3011
|
}
|
|
2916
3012
|
return inferLoopStatusFromMessages(messages);
|
|
2917
3013
|
}
|
|
2918
|
-
function
|
|
3014
|
+
function isRecord5(value) {
|
|
2919
3015
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2920
3016
|
}
|
|
3017
|
+
function toSelectionMap(value) {
|
|
3018
|
+
if (!isRecord5(value)) return {};
|
|
3019
|
+
const entries = Object.entries(value).map(([questionKey, optionIndexes]) => {
|
|
3020
|
+
if (!Array.isArray(optionIndexes)) return null;
|
|
3021
|
+
const parsedIndexes = optionIndexes.map((item) => typeof item === "number" ? item : Number(item)).filter((item) => Number.isInteger(item));
|
|
3022
|
+
return [Number(questionKey), parsedIndexes];
|
|
3023
|
+
}).filter((entry) => entry !== null);
|
|
3024
|
+
return Object.fromEntries(entries);
|
|
3025
|
+
}
|
|
3026
|
+
function toCustomMap(value) {
|
|
3027
|
+
if (!isRecord5(value)) return {};
|
|
3028
|
+
const entries = Object.entries(value).filter(([, text]) => typeof text === "string").map(([questionKey, text]) => [Number(questionKey), text]);
|
|
3029
|
+
return Object.fromEntries(entries);
|
|
3030
|
+
}
|
|
3031
|
+
function extractAskAnswers(turns) {
|
|
3032
|
+
const answers = {};
|
|
3033
|
+
for (const turn of turns) {
|
|
3034
|
+
for (const block of turn.blocks) {
|
|
3035
|
+
if (block.type !== "ask_user_answer" || typeof block.tool_call_id !== "string") continue;
|
|
3036
|
+
if (!isRecord5(block.content)) continue;
|
|
3037
|
+
const note = typeof block.content.note === "string" ? block.content.note.trim() : "";
|
|
3038
|
+
answers[block.tool_call_id] = {
|
|
3039
|
+
selections: toSelectionMap(block.content.selections),
|
|
3040
|
+
custom: toCustomMap(block.content.custom),
|
|
3041
|
+
...note ? { note } : {}
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
return answers;
|
|
3046
|
+
}
|
|
2921
3047
|
function parentForkToolCallIdFromTurn(turn) {
|
|
2922
3048
|
if (typeof turn.parent_fork_tool_call_id === "string" && turn.parent_fork_tool_call_id.length > 0) {
|
|
2923
3049
|
return turn.parent_fork_tool_call_id;
|
|
2924
3050
|
}
|
|
2925
3051
|
for (const block of turn.blocks) {
|
|
2926
|
-
if (block.type !== "system_notification" || !
|
|
3052
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) continue;
|
|
2927
3053
|
const metadata = block.content.metadata;
|
|
2928
|
-
if (!
|
|
3054
|
+
if (!isRecord5(metadata)) continue;
|
|
2929
3055
|
const parentId = metadata.parent_fork_tool_call_id;
|
|
2930
3056
|
if (typeof parentId === "string" && parentId.length > 0) return parentId;
|
|
2931
3057
|
}
|
|
@@ -2942,16 +3068,16 @@ function buildMessageContent2(turn) {
|
|
|
2942
3068
|
}
|
|
2943
3069
|
function workspaceNotificationContent(turn) {
|
|
2944
3070
|
const block = turn.blocks.find(
|
|
2945
|
-
(candidate) => candidate.type === "system_notification" &&
|
|
3071
|
+
(candidate) => candidate.type === "system_notification" && isRecord5(candidate.content) && candidate.content.notification_type === "workspace_change"
|
|
2946
3072
|
);
|
|
2947
|
-
if (!block || !
|
|
3073
|
+
if (!block || !isRecord5(block.content)) return "";
|
|
2948
3074
|
const title = typeof block.content.title === "string" ? block.content.title.trim() : "";
|
|
2949
3075
|
const detail = typeof block.content.detail === "string" ? block.content.detail.trim() : "";
|
|
2950
3076
|
return [title ? `**${title}**` : "", detail].filter(Boolean).join("\n\n");
|
|
2951
3077
|
}
|
|
2952
3078
|
function askUserAnswerContent(turn) {
|
|
2953
3079
|
const answerBlock = turn.blocks.find((block) => block.type === "ask_user_answer");
|
|
2954
|
-
if (!answerBlock || !
|
|
3080
|
+
if (!answerBlock || !isRecord5(answerBlock.content)) return null;
|
|
2955
3081
|
const answer = answerBlock.content.answer;
|
|
2956
3082
|
return typeof answer === "string" && answer.trim().length > 0 ? answer : null;
|
|
2957
3083
|
}
|
|
@@ -2971,6 +3097,19 @@ function extractModeFromBlocks(blocks) {
|
|
|
2971
3097
|
return null;
|
|
2972
3098
|
}
|
|
2973
3099
|
function projectionToMessage(turn) {
|
|
3100
|
+
if (turn.kind === "context") {
|
|
3101
|
+
const context = contextProjectionData(turn);
|
|
3102
|
+
if (!context) return null;
|
|
3103
|
+
return {
|
|
3104
|
+
role: "assistant",
|
|
3105
|
+
content: "",
|
|
3106
|
+
kind: "context",
|
|
3107
|
+
context,
|
|
3108
|
+
loop_name: turn.loop_id,
|
|
3109
|
+
entry_id: turn.turn_id,
|
|
3110
|
+
status: turn.status
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
2974
3113
|
if (turn.kind === "compaction" && turn.compaction_id) {
|
|
2975
3114
|
return {
|
|
2976
3115
|
role: "assistant",
|
|
@@ -3143,7 +3282,7 @@ function orderTurns(turns) {
|
|
|
3143
3282
|
function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
3144
3283
|
const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]));
|
|
3145
3284
|
const optimisticUserTurn = currentTurns.find(
|
|
3146
|
-
(turn) => turn.role === "user" && turn.turn_id.startsWith("local-user-")
|
|
3285
|
+
(turn) => turn.role === "user" && (turn.kind ?? "message") === "message" && turn.turn_id.startsWith("local-user-")
|
|
3147
3286
|
);
|
|
3148
3287
|
let optimisticUserMatched = false;
|
|
3149
3288
|
return incomingTurns.map((turn) => {
|
|
@@ -3152,7 +3291,7 @@ function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
|
3152
3291
|
const currentRenderId = current.client_render_id;
|
|
3153
3292
|
return turn.client_render_id || !currentRenderId ? turn : { ...turn, client_render_id: currentRenderId };
|
|
3154
3293
|
}
|
|
3155
|
-
if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && !turn.turn_id.startsWith("local-user-")) {
|
|
3294
|
+
if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && (turn.kind ?? "message") === "message" && !turn.turn_id.startsWith("local-user-")) {
|
|
3156
3295
|
optimisticUserMatched = true;
|
|
3157
3296
|
return { ...turn, client_render_id: optimisticUserTurn.turn_id };
|
|
3158
3297
|
}
|
|
@@ -3188,12 +3327,23 @@ function withTurns(state, turns) {
|
|
|
3188
3327
|
});
|
|
3189
3328
|
const mergedMessages = preservedErrors.length > 0 ? [...messagesWithRenderIds, ...preservedErrors] : messagesWithRenderIds;
|
|
3190
3329
|
const latestMode = [...orderedTurns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
|
|
3330
|
+
const askAnswersFromHistory = extractAskAnswers(orderedTurns);
|
|
3331
|
+
const presentToolCallIds = new Set(
|
|
3332
|
+
orderedTurns.flatMap((turn) => turn.tool_calls.map((toolCall) => toolCall.id))
|
|
3333
|
+
);
|
|
3334
|
+
const askAnswers = { ...askAnswersFromHistory };
|
|
3335
|
+
for (const [toolCallId, answer] of Object.entries(state.askAnswers)) {
|
|
3336
|
+
if (!(toolCallId in askAnswers) && presentToolCallIds.has(toolCallId)) {
|
|
3337
|
+
askAnswers[toolCallId] = answer;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3191
3340
|
return {
|
|
3192
3341
|
...state,
|
|
3193
3342
|
turns: orderedTurns,
|
|
3194
3343
|
messages: mergedMessages,
|
|
3195
3344
|
agentLoops: stableAgentLoops,
|
|
3196
3345
|
activeCompaction,
|
|
3346
|
+
askAnswers,
|
|
3197
3347
|
mode: latestMode ?? state.mode,
|
|
3198
3348
|
// 历史恢复时 chat:end(paused) 可能已不在 socket replay 缓存中;
|
|
3199
3349
|
// awaiting_answer 是投影里的持久权威状态,必须据此恢复问答交互。
|
|
@@ -3283,18 +3433,18 @@ function markStreamingTurns(state, turnStatus, toolCallStatus) {
|
|
|
3283
3433
|
// src/session/agent-session.ts
|
|
3284
3434
|
var OOM_MESSAGE = "\u6C99\u76D2\u5185\u5B58\u4F7F\u7528\u8D85\u51FA\u9650\u5236\uFF0C\u5DF2\u81EA\u52A8\u91CD\u542F\u3002\u5982\u679C\u7ECF\u5E38\u89E6\u53D1\uFF0C\u53EF\u4EE5\u8054\u7CFB\u7BA1\u7406\u5458\u8C03\u6574\u989D\u5EA6\u3002";
|
|
3285
3435
|
var OOM_KEYWORDS_RE = /(?:\b(?:exit_code|ExitedWith|exited with)|退出码)\D*(?<!\d)137(?!\d)/i;
|
|
3286
|
-
function
|
|
3436
|
+
function isRecord6(value) {
|
|
3287
3437
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3288
3438
|
}
|
|
3289
3439
|
function isOomText(value) {
|
|
3290
3440
|
return typeof value === "string" && OOM_KEYWORDS_RE.test(value);
|
|
3291
3441
|
}
|
|
3292
3442
|
function parseJsonRecord(value) {
|
|
3293
|
-
if (
|
|
3443
|
+
if (isRecord6(value)) return value;
|
|
3294
3444
|
if (typeof value !== "string") return null;
|
|
3295
3445
|
try {
|
|
3296
3446
|
const parsed = JSON.parse(value);
|
|
3297
|
-
return
|
|
3447
|
+
return isRecord6(parsed) ? parsed : null;
|
|
3298
3448
|
} catch {
|
|
3299
3449
|
return null;
|
|
3300
3450
|
}
|
|
@@ -3341,7 +3491,7 @@ function hasChatRunEvent2(events) {
|
|
|
3341
3491
|
);
|
|
3342
3492
|
}
|
|
3343
3493
|
function isUiMetaLike(value) {
|
|
3344
|
-
return
|
|
3494
|
+
return isRecord6(value) && ("resourceHTML" in value || "resourceUri" in value || "resourceURI" in value);
|
|
3345
3495
|
}
|
|
3346
3496
|
var AgentSession = class _AgentSession {
|
|
3347
3497
|
sessionId;
|
|
@@ -3492,7 +3642,7 @@ var AgentSession = class _AgentSession {
|
|
|
3492
3642
|
if (this.getAppContext) {
|
|
3493
3643
|
try {
|
|
3494
3644
|
const rawContext = await this.getAppContext();
|
|
3495
|
-
if (!
|
|
3645
|
+
if (!isRecord6(rawContext)) {
|
|
3496
3646
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3497
3647
|
}
|
|
3498
3648
|
const serialized = JSON.stringify(rawContext);
|
|
@@ -3500,7 +3650,7 @@ var AgentSession = class _AgentSession {
|
|
|
3500
3650
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE\u53EF\u5E8F\u5217\u5316\u7684 JSON \u5BF9\u8C61");
|
|
3501
3651
|
}
|
|
3502
3652
|
const normalized = JSON.parse(serialized);
|
|
3503
|
-
if (!
|
|
3653
|
+
if (!isRecord6(normalized)) {
|
|
3504
3654
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3505
3655
|
}
|
|
3506
3656
|
appContext = normalized;
|
|
@@ -3883,9 +4033,9 @@ var AgentSession = class _AgentSession {
|
|
|
3883
4033
|
detail,
|
|
3884
4034
|
status,
|
|
3885
4035
|
loopId,
|
|
3886
|
-
metadata:
|
|
4036
|
+
metadata: isRecord6(notification.metadata) ? notification.metadata : void 0
|
|
3887
4037
|
});
|
|
3888
|
-
if (notificationType === "bg:started" &&
|
|
4038
|
+
if (notificationType === "bg:started" && isRecord6(notification.metadata)) {
|
|
3889
4039
|
const taskId = typeof notification.metadata.task_id === "string" ? notification.metadata.task_id : "";
|
|
3890
4040
|
if (taskId) {
|
|
3891
4041
|
this.emitter.emit("backgroundTask", {
|
|
@@ -4015,7 +4165,7 @@ var AgentSession = class _AgentSession {
|
|
|
4015
4165
|
title: ui.title ?? "\u5DE5\u5177\u9884\u89C8"
|
|
4016
4166
|
});
|
|
4017
4167
|
}
|
|
4018
|
-
if (block.type === "system_notification" &&
|
|
4168
|
+
if (block.type === "system_notification" && isRecord6(block.content)) {
|
|
4019
4169
|
this._handleSystemNotification(turn.loop_id, block.content);
|
|
4020
4170
|
}
|
|
4021
4171
|
}
|
|
@@ -4499,7 +4649,7 @@ function resolveAuthToken(options) {
|
|
|
4499
4649
|
|
|
4500
4650
|
// src/version.ts
|
|
4501
4651
|
var SDK_NAME = "agent-client";
|
|
4502
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4652
|
+
var SDK_VERSION = true ? "2610.0.0-beta.18" : "1.1.1";
|
|
4503
4653
|
|
|
4504
4654
|
// src/socket.ts
|
|
4505
4655
|
function withSdkIdentity(auth) {
|
|
@@ -4693,7 +4843,7 @@ var BladeClient = class {
|
|
|
4693
4843
|
const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {
|
|
4694
4844
|
method,
|
|
4695
4845
|
body: init.body,
|
|
4696
|
-
credentials: init.credentials ?? "
|
|
4846
|
+
credentials: init.credentials ?? "include",
|
|
4697
4847
|
headers: this.buildHeaders(url, init.headers),
|
|
4698
4848
|
signal: init.signal
|
|
4699
4849
|
});
|
|
@@ -4911,7 +5061,7 @@ function defaultDocumentBaseUrl() {
|
|
|
4911
5061
|
if (typeof location !== "undefined" && location.origin) return `${location.origin}/`;
|
|
4912
5062
|
return document.baseURI;
|
|
4913
5063
|
}
|
|
4914
|
-
function
|
|
5064
|
+
function isRecord7(value) {
|
|
4915
5065
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4916
5066
|
}
|
|
4917
5067
|
function normalizeServiceUrl(value) {
|
|
@@ -4927,7 +5077,7 @@ function normalizeServiceUrl(value) {
|
|
|
4927
5077
|
}
|
|
4928
5078
|
}
|
|
4929
5079
|
function parsePlatformEndpoints(value) {
|
|
4930
|
-
if (!
|
|
5080
|
+
if (!isRecord7(value) || !isRecord7(value.services)) return null;
|
|
4931
5081
|
const services = {};
|
|
4932
5082
|
for (const name of PLATFORM_SERVICE_NAMES) {
|
|
4933
5083
|
if (!(name in value.services)) continue;
|
|
@@ -5094,9 +5244,11 @@ export {
|
|
|
5094
5244
|
buildMessageContent,
|
|
5095
5245
|
connectEmbedded,
|
|
5096
5246
|
contentPreview,
|
|
5247
|
+
contextProjectionData,
|
|
5097
5248
|
createInitialSessionState,
|
|
5098
5249
|
createSocket,
|
|
5099
5250
|
extractTextAttachments,
|
|
5251
|
+
getContextDisplayState,
|
|
5100
5252
|
getFileParts,
|
|
5101
5253
|
getImageParts,
|
|
5102
5254
|
getTextContent,
|