@blade-hq/agent-client 2610.0.0-beta.2 → 2610.0.0-beta.21
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 +29 -3
- package/dist/index.d.ts +5 -1
- package/dist/index.js +324 -55
- package/dist/index.js.map +1 -1
- package/dist/platform-endpoints.d.ts +14 -0
- package/dist/schemas/context.d.ts +34 -0
- package/dist/schemas/event.d.ts +9 -0
- package/dist/schemas/message.d.ts +5 -0
- package/dist/schemas/projection.d.ts +12 -1
- package/dist/session/agent-session.d.ts +2 -0
- package/dist/session/state.d.ts +4 -1
- package/dist/shared/projection/builder.d.ts +2 -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/dist/types/socket-events.d.ts +11 -0
- package/package.json +1 -1
- package/public-api.md +121 -2
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":
|
|
@@ -1165,6 +1248,8 @@ var ClientProjectionBuilder = class {
|
|
|
1165
1248
|
return this.syncPatch(state);
|
|
1166
1249
|
case "llm:tool_call:created":
|
|
1167
1250
|
return this.onToolCallCreated(state, payload);
|
|
1251
|
+
case "llm:tool_call:arguments:delta":
|
|
1252
|
+
return this.onToolCallArgumentsDelta(state, payload);
|
|
1168
1253
|
case "llm:response:done":
|
|
1169
1254
|
return this.onResponseDone(state, loopId, payload);
|
|
1170
1255
|
case "tool:result:delta":
|
|
@@ -1232,6 +1317,11 @@ var ClientProjectionBuilder = class {
|
|
|
1232
1317
|
}
|
|
1233
1318
|
return null;
|
|
1234
1319
|
}
|
|
1320
|
+
onContextEntry(payload) {
|
|
1321
|
+
if (!isRecord3(payload.entry)) return null;
|
|
1322
|
+
const turn = buildContextTurn(payload.entry, this.nextSeq());
|
|
1323
|
+
return turn ? [{ kind: "upsert", turn }] : null;
|
|
1324
|
+
}
|
|
1235
1325
|
onLoopTurn(loopId, payload) {
|
|
1236
1326
|
let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`));
|
|
1237
1327
|
let memoryRefs = null;
|
|
@@ -1288,11 +1378,11 @@ var ClientProjectionBuilder = class {
|
|
|
1288
1378
|
loopId,
|
|
1289
1379
|
toolCallId: optStr(payload.tool_call_id) ?? void 0,
|
|
1290
1380
|
toolName: toolNameFromPayload(payload) ?? void 0,
|
|
1291
|
-
workspacePath:
|
|
1381
|
+
workspacePath: isRecord3(payload.workspace_change) ? optStr(payload.workspace_change.to) ?? void 0 : void 0
|
|
1292
1382
|
}
|
|
1293
1383
|
];
|
|
1294
1384
|
const change = payload.workspace_change;
|
|
1295
|
-
if (
|
|
1385
|
+
if (isRecord3(change)) {
|
|
1296
1386
|
const source = optStr(change.source) ?? "";
|
|
1297
1387
|
const projectName = optStr(change.project_name) ?? "";
|
|
1298
1388
|
const fromPath = optStr(change.from) ?? "";
|
|
@@ -1430,13 +1520,7 @@ var ClientProjectionBuilder = class {
|
|
|
1430
1520
|
}
|
|
1431
1521
|
onToolCallCreated(state, payload) {
|
|
1432
1522
|
if ("arguments_delta" in payload) {
|
|
1433
|
-
|
|
1434
|
-
const toolCallId2 = String(payload.id ?? "");
|
|
1435
|
-
if (delta && toolCallId2) {
|
|
1436
|
-
appendToolCallArguments(state, toolCallId2, delta);
|
|
1437
|
-
return this.syncPatch(state);
|
|
1438
|
-
}
|
|
1439
|
-
return null;
|
|
1523
|
+
return this.onToolCallArgumentsDelta(state, payload);
|
|
1440
1524
|
}
|
|
1441
1525
|
const toolCallId = String(payload.id ?? "");
|
|
1442
1526
|
const toolName = toolNameFromPayload(payload);
|
|
@@ -1445,6 +1529,13 @@ var ClientProjectionBuilder = class {
|
|
|
1445
1529
|
upsertToolCall(state, toolCallId, toolName, displayName, args);
|
|
1446
1530
|
return this.syncPatch(state);
|
|
1447
1531
|
}
|
|
1532
|
+
onToolCallArgumentsDelta(state, payload) {
|
|
1533
|
+
const delta = String(payload.arguments_delta ?? "");
|
|
1534
|
+
const toolCallId = String(payload.id ?? "");
|
|
1535
|
+
if (!delta || !toolCallId) return null;
|
|
1536
|
+
appendToolCallArguments(state, toolCallId, delta);
|
|
1537
|
+
return this.syncPatch(state);
|
|
1538
|
+
}
|
|
1448
1539
|
onResponseDone(state, loopId, payload) {
|
|
1449
1540
|
state.responseDone = true;
|
|
1450
1541
|
const model = optStr(payload.model);
|
|
@@ -1754,7 +1845,7 @@ var ClientProjectionBuilder = class {
|
|
|
1754
1845
|
return `${prefix}:${this.syntheticCounter}:${hex}`;
|
|
1755
1846
|
}
|
|
1756
1847
|
};
|
|
1757
|
-
function
|
|
1848
|
+
function isRecord3(value) {
|
|
1758
1849
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1759
1850
|
}
|
|
1760
1851
|
function optStr(value) {
|
|
@@ -1790,7 +1881,7 @@ function projectHistory(entries) {
|
|
|
1790
1881
|
const kind = String(entry.kind ?? "");
|
|
1791
1882
|
const loopId = String(entry.loop_name ?? "root");
|
|
1792
1883
|
const id = String(entry.id ?? `history-${sequence + 1}`);
|
|
1793
|
-
if (kind === "post_chat_followup" &&
|
|
1884
|
+
if (kind === "post_chat_followup" && isRecord4(entry.data)) {
|
|
1794
1885
|
const assistantEntryId = String(entry.data.assistant_entry_id ?? "");
|
|
1795
1886
|
if (latestRootMessage?.role === "assistant" && latestRootMessage.turn_id === assistantEntryId) {
|
|
1796
1887
|
const followup = normalizePostChatFollowup(entry.data, assistantEntryId);
|
|
@@ -1798,7 +1889,15 @@ function projectHistory(entries) {
|
|
|
1798
1889
|
}
|
|
1799
1890
|
continue;
|
|
1800
1891
|
}
|
|
1801
|
-
if (kind === "
|
|
1892
|
+
if (kind === "context") {
|
|
1893
|
+
const turn = buildContextTurn(entry, sequence + 1);
|
|
1894
|
+
if (turn) {
|
|
1895
|
+
sequence += 1;
|
|
1896
|
+
turns.push(turn);
|
|
1897
|
+
}
|
|
1898
|
+
continue;
|
|
1899
|
+
}
|
|
1900
|
+
if (kind === "message" && isRecord4(entry.message)) {
|
|
1802
1901
|
const message = entry.message;
|
|
1803
1902
|
const role = String(message.role ?? "");
|
|
1804
1903
|
if (role === "tool") {
|
|
@@ -1830,7 +1929,7 @@ function projectHistory(entries) {
|
|
|
1830
1929
|
blocks,
|
|
1831
1930
|
tool_calls: toolCalls,
|
|
1832
1931
|
model: stringOrNull(message.model),
|
|
1833
|
-
usage:
|
|
1932
|
+
usage: isRecord4(message._usage) ? { ...message._usage } : null,
|
|
1834
1933
|
duration_ms: numberOrZero(message._duration_ms),
|
|
1835
1934
|
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
|
|
1836
1935
|
};
|
|
@@ -1849,7 +1948,7 @@ function projectHistory(entries) {
|
|
|
1849
1948
|
if (kind === "mode_change") {
|
|
1850
1949
|
turns.push(markerTurn(id, ++sequence, loopId, "mode_change", entry.data ?? {}));
|
|
1851
1950
|
} else if (kind === "workspace_change") {
|
|
1852
|
-
const change =
|
|
1951
|
+
const change = isRecord4(entry.data) ? entry.data : {};
|
|
1853
1952
|
const source = stringOrNull(change.source) ?? "";
|
|
1854
1953
|
const projectName = stringOrNull(change.project_name) ?? "";
|
|
1855
1954
|
const fromPath = stringOrNull(change.from) ?? "";
|
|
@@ -1890,7 +1989,7 @@ function projectHistory(entries) {
|
|
|
1890
1989
|
} else if (kind === "compaction" || kind === "tool_result_archive") {
|
|
1891
1990
|
const data = entry.data ?? {};
|
|
1892
1991
|
const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`);
|
|
1893
|
-
let content =
|
|
1992
|
+
let content = isRecord4(entry.message) ? entry.message.content : void 0;
|
|
1894
1993
|
if (kind === "tool_result_archive") {
|
|
1895
1994
|
const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0;
|
|
1896
1995
|
content = `<compaction-summary>
|
|
@@ -1905,11 +2004,11 @@ function projectHistory(entries) {
|
|
|
1905
2004
|
);
|
|
1906
2005
|
} else if (kind === "child_pause") {
|
|
1907
2006
|
const data = entry.data ?? {};
|
|
1908
|
-
const sourceLoop =
|
|
2007
|
+
const sourceLoop = isRecord4(data.source_loop) ? data.source_loop : {};
|
|
1909
2008
|
const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? "");
|
|
1910
2009
|
const childToolCallId = String(data.child_pause_tool_call_id ?? "");
|
|
1911
2010
|
const parentToolCallId = String(data.parent_fork_tool_call_id ?? "");
|
|
1912
|
-
const pauseToolData =
|
|
2011
|
+
const pauseToolData = isRecord4(data.pause_tool_data) ? data.pause_tool_data : {};
|
|
1913
2012
|
const description = String(sourceLoop.description ?? "");
|
|
1914
2013
|
applyAskUserPauseToTurn(
|
|
1915
2014
|
latestAssistantByLoop.get(childLoopId),
|
|
@@ -1997,15 +2096,15 @@ function parseToolArguments(value) {
|
|
|
1997
2096
|
if (!value) return {};
|
|
1998
2097
|
try {
|
|
1999
2098
|
const parsed = JSON.parse(value);
|
|
2000
|
-
return
|
|
2099
|
+
return isRecord4(parsed) ? parsed : {};
|
|
2001
2100
|
} catch {
|
|
2002
2101
|
return {};
|
|
2003
2102
|
}
|
|
2004
2103
|
}
|
|
2005
2104
|
function buildToolCalls(value) {
|
|
2006
2105
|
if (!Array.isArray(value)) return [];
|
|
2007
|
-
return value.filter(
|
|
2008
|
-
const fn =
|
|
2106
|
+
return value.filter(isRecord4).map((raw) => {
|
|
2107
|
+
const fn = isRecord4(raw.function) ? raw.function : {};
|
|
2009
2108
|
const name = String(fn.name ?? "");
|
|
2010
2109
|
return {
|
|
2011
2110
|
id: String(raw.id ?? ""),
|
|
@@ -2025,7 +2124,7 @@ function buildBlocks(message, toolCalls) {
|
|
|
2025
2124
|
blocks.push({ type: "text", content: displayContent });
|
|
2026
2125
|
} else if (Array.isArray(stored)) {
|
|
2027
2126
|
for (const raw of stored) {
|
|
2028
|
-
if (!
|
|
2127
|
+
if (!isRecord4(raw)) continue;
|
|
2029
2128
|
const type3 = String(raw.type ?? "");
|
|
2030
2129
|
if (type3 === "thinking") blocks.push({ type: type3, content: raw.thinking ?? raw.content ?? "" });
|
|
2031
2130
|
if (type3 === "text") blocks.push({ type: type3, content: raw.text ?? raw.content ?? "" });
|
|
@@ -2058,7 +2157,7 @@ function markerTurn(id, sequence, loopId, type3, content, toolCallId = null) {
|
|
|
2058
2157
|
duration_ms: 0
|
|
2059
2158
|
};
|
|
2060
2159
|
}
|
|
2061
|
-
function
|
|
2160
|
+
function isRecord4(value) {
|
|
2062
2161
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2063
2162
|
}
|
|
2064
2163
|
function stringOrNull(value) {
|
|
@@ -2903,10 +3002,10 @@ function inferLoopStatusFromMessages(messages) {
|
|
|
2903
3002
|
}
|
|
2904
3003
|
function inferLoopStatusFromTurns(turns, messages) {
|
|
2905
3004
|
const latestAgentNotification = [...turns].reverse().flatMap((turn) => turn.blocks).find((block) => {
|
|
2906
|
-
if (block.type !== "system_notification" || !
|
|
3005
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) return false;
|
|
2907
3006
|
return block.content.notification_type === "agent:start" || block.content.notification_type === "agent:end";
|
|
2908
3007
|
});
|
|
2909
|
-
if (latestAgentNotification?.type === "system_notification" &&
|
|
3008
|
+
if (latestAgentNotification?.type === "system_notification" && isRecord5(latestAgentNotification.content)) {
|
|
2910
3009
|
const notificationType = latestAgentNotification.content.notification_type;
|
|
2911
3010
|
const status = latestAgentNotification.content.status;
|
|
2912
3011
|
if (notificationType === "agent:start" || status === "running") return "running";
|
|
@@ -2915,17 +3014,47 @@ function inferLoopStatusFromTurns(turns, messages) {
|
|
|
2915
3014
|
}
|
|
2916
3015
|
return inferLoopStatusFromMessages(messages);
|
|
2917
3016
|
}
|
|
2918
|
-
function
|
|
3017
|
+
function isRecord5(value) {
|
|
2919
3018
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2920
3019
|
}
|
|
3020
|
+
function toSelectionMap(value) {
|
|
3021
|
+
if (!isRecord5(value)) return {};
|
|
3022
|
+
const entries = Object.entries(value).map(([questionKey, optionIndexes]) => {
|
|
3023
|
+
if (!Array.isArray(optionIndexes)) return null;
|
|
3024
|
+
const parsedIndexes = optionIndexes.map((item) => typeof item === "number" ? item : Number(item)).filter((item) => Number.isInteger(item));
|
|
3025
|
+
return [Number(questionKey), parsedIndexes];
|
|
3026
|
+
}).filter((entry) => entry !== null);
|
|
3027
|
+
return Object.fromEntries(entries);
|
|
3028
|
+
}
|
|
3029
|
+
function toCustomMap(value) {
|
|
3030
|
+
if (!isRecord5(value)) return {};
|
|
3031
|
+
const entries = Object.entries(value).filter(([, text]) => typeof text === "string").map(([questionKey, text]) => [Number(questionKey), text]);
|
|
3032
|
+
return Object.fromEntries(entries);
|
|
3033
|
+
}
|
|
3034
|
+
function extractAskAnswers(turns) {
|
|
3035
|
+
const answers = {};
|
|
3036
|
+
for (const turn of turns) {
|
|
3037
|
+
for (const block of turn.blocks) {
|
|
3038
|
+
if (block.type !== "ask_user_answer" || typeof block.tool_call_id !== "string") continue;
|
|
3039
|
+
if (!isRecord5(block.content)) continue;
|
|
3040
|
+
const note = typeof block.content.note === "string" ? block.content.note.trim() : "";
|
|
3041
|
+
answers[block.tool_call_id] = {
|
|
3042
|
+
selections: toSelectionMap(block.content.selections),
|
|
3043
|
+
custom: toCustomMap(block.content.custom),
|
|
3044
|
+
...note ? { note } : {}
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
return answers;
|
|
3049
|
+
}
|
|
2921
3050
|
function parentForkToolCallIdFromTurn(turn) {
|
|
2922
3051
|
if (typeof turn.parent_fork_tool_call_id === "string" && turn.parent_fork_tool_call_id.length > 0) {
|
|
2923
3052
|
return turn.parent_fork_tool_call_id;
|
|
2924
3053
|
}
|
|
2925
3054
|
for (const block of turn.blocks) {
|
|
2926
|
-
if (block.type !== "system_notification" || !
|
|
3055
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) continue;
|
|
2927
3056
|
const metadata = block.content.metadata;
|
|
2928
|
-
if (!
|
|
3057
|
+
if (!isRecord5(metadata)) continue;
|
|
2929
3058
|
const parentId = metadata.parent_fork_tool_call_id;
|
|
2930
3059
|
if (typeof parentId === "string" && parentId.length > 0) return parentId;
|
|
2931
3060
|
}
|
|
@@ -2942,16 +3071,16 @@ function buildMessageContent2(turn) {
|
|
|
2942
3071
|
}
|
|
2943
3072
|
function workspaceNotificationContent(turn) {
|
|
2944
3073
|
const block = turn.blocks.find(
|
|
2945
|
-
(candidate) => candidate.type === "system_notification" &&
|
|
3074
|
+
(candidate) => candidate.type === "system_notification" && isRecord5(candidate.content) && candidate.content.notification_type === "workspace_change"
|
|
2946
3075
|
);
|
|
2947
|
-
if (!block || !
|
|
3076
|
+
if (!block || !isRecord5(block.content)) return "";
|
|
2948
3077
|
const title = typeof block.content.title === "string" ? block.content.title.trim() : "";
|
|
2949
3078
|
const detail = typeof block.content.detail === "string" ? block.content.detail.trim() : "";
|
|
2950
3079
|
return [title ? `**${title}**` : "", detail].filter(Boolean).join("\n\n");
|
|
2951
3080
|
}
|
|
2952
3081
|
function askUserAnswerContent(turn) {
|
|
2953
3082
|
const answerBlock = turn.blocks.find((block) => block.type === "ask_user_answer");
|
|
2954
|
-
if (!answerBlock || !
|
|
3083
|
+
if (!answerBlock || !isRecord5(answerBlock.content)) return null;
|
|
2955
3084
|
const answer = answerBlock.content.answer;
|
|
2956
3085
|
return typeof answer === "string" && answer.trim().length > 0 ? answer : null;
|
|
2957
3086
|
}
|
|
@@ -2971,6 +3100,19 @@ function extractModeFromBlocks(blocks) {
|
|
|
2971
3100
|
return null;
|
|
2972
3101
|
}
|
|
2973
3102
|
function projectionToMessage(turn) {
|
|
3103
|
+
if (turn.kind === "context") {
|
|
3104
|
+
const context = contextProjectionData(turn);
|
|
3105
|
+
if (!context) return null;
|
|
3106
|
+
return {
|
|
3107
|
+
role: "assistant",
|
|
3108
|
+
content: "",
|
|
3109
|
+
kind: "context",
|
|
3110
|
+
context,
|
|
3111
|
+
loop_name: turn.loop_id,
|
|
3112
|
+
entry_id: turn.turn_id,
|
|
3113
|
+
status: turn.status
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
2974
3116
|
if (turn.kind === "compaction" && turn.compaction_id) {
|
|
2975
3117
|
return {
|
|
2976
3118
|
role: "assistant",
|
|
@@ -3140,6 +3282,25 @@ function orderTurns(turns) {
|
|
|
3140
3282
|
}
|
|
3141
3283
|
return turns;
|
|
3142
3284
|
}
|
|
3285
|
+
function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
3286
|
+
const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]));
|
|
3287
|
+
const optimisticUserTurn = currentTurns.find(
|
|
3288
|
+
(turn) => turn.role === "user" && (turn.kind ?? "message") === "message" && turn.turn_id.startsWith("local-user-")
|
|
3289
|
+
);
|
|
3290
|
+
let optimisticUserMatched = false;
|
|
3291
|
+
return incomingTurns.map((turn) => {
|
|
3292
|
+
const current = currentById.get(turn.turn_id);
|
|
3293
|
+
if (current) {
|
|
3294
|
+
const currentRenderId = current.client_render_id;
|
|
3295
|
+
return turn.client_render_id || !currentRenderId ? turn : { ...turn, client_render_id: currentRenderId };
|
|
3296
|
+
}
|
|
3297
|
+
if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && (turn.kind ?? "message") === "message" && !turn.turn_id.startsWith("local-user-")) {
|
|
3298
|
+
optimisticUserMatched = true;
|
|
3299
|
+
return { ...turn, client_render_id: optimisticUserTurn.turn_id };
|
|
3300
|
+
}
|
|
3301
|
+
return turn;
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3143
3304
|
function areAgentLoopsEqual(left, right) {
|
|
3144
3305
|
if (!left) return Object.keys(right).length === 0;
|
|
3145
3306
|
const leftEntries = Object.entries(left);
|
|
@@ -3151,7 +3312,7 @@ function areAgentLoopsEqual(left, right) {
|
|
|
3151
3312
|
});
|
|
3152
3313
|
}
|
|
3153
3314
|
function withTurns(state, turns) {
|
|
3154
|
-
const orderedTurns = orderTurns(turns);
|
|
3315
|
+
const orderedTurns = orderTurns(reconcileOptimisticUserTurns(state.turns, turns));
|
|
3155
3316
|
const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
|
|
3156
3317
|
const isWaitingForInput = orderedTurns.some(
|
|
3157
3318
|
(turn) => turn.tool_calls.some((toolCall) => toolCall.status === "awaiting_answer")
|
|
@@ -3161,14 +3322,31 @@ function withTurns(state, turns) {
|
|
|
3161
3322
|
const preservedErrors = lastTurnId ? state.messages.filter(
|
|
3162
3323
|
(m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
|
|
3163
3324
|
) : [];
|
|
3164
|
-
const
|
|
3325
|
+
const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]));
|
|
3326
|
+
const messagesWithRenderIds = messages.map((message) => {
|
|
3327
|
+
if (!message.entry_id) return message;
|
|
3328
|
+
const renderId = turnById.get(message.entry_id)?.client_render_id;
|
|
3329
|
+
return renderId ? { ...message, render_id: renderId } : message;
|
|
3330
|
+
});
|
|
3331
|
+
const mergedMessages = preservedErrors.length > 0 ? [...messagesWithRenderIds, ...preservedErrors] : messagesWithRenderIds;
|
|
3165
3332
|
const latestMode = [...orderedTurns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
|
|
3333
|
+
const askAnswersFromHistory = extractAskAnswers(orderedTurns);
|
|
3334
|
+
const presentToolCallIds = new Set(
|
|
3335
|
+
orderedTurns.flatMap((turn) => turn.tool_calls.map((toolCall) => toolCall.id))
|
|
3336
|
+
);
|
|
3337
|
+
const askAnswers = { ...askAnswersFromHistory };
|
|
3338
|
+
for (const [toolCallId, answer] of Object.entries(state.askAnswers)) {
|
|
3339
|
+
if (!(toolCallId in askAnswers) && presentToolCallIds.has(toolCallId)) {
|
|
3340
|
+
askAnswers[toolCallId] = answer;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3166
3343
|
return {
|
|
3167
3344
|
...state,
|
|
3168
3345
|
turns: orderedTurns,
|
|
3169
3346
|
messages: mergedMessages,
|
|
3170
3347
|
agentLoops: stableAgentLoops,
|
|
3171
3348
|
activeCompaction,
|
|
3349
|
+
askAnswers,
|
|
3172
3350
|
mode: latestMode ?? state.mode,
|
|
3173
3351
|
// 历史恢复时 chat:end(paused) 可能已不在 socket replay 缓存中;
|
|
3174
3352
|
// awaiting_answer 是投影里的持久权威状态,必须据此恢复问答交互。
|
|
@@ -3196,14 +3374,17 @@ function addUserMessage(state, content) {
|
|
|
3196
3374
|
}
|
|
3197
3375
|
function upsertTurn(state, turn) {
|
|
3198
3376
|
let existing = [...state.turns];
|
|
3199
|
-
|
|
3200
|
-
|
|
3377
|
+
const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn]);
|
|
3378
|
+
if (nextTurn.client_render_id && turn.role === "user") {
|
|
3379
|
+
existing = existing.filter(
|
|
3380
|
+
(item) => !(item.role === "user" && item.turn_id.startsWith("local-user-"))
|
|
3381
|
+
);
|
|
3201
3382
|
}
|
|
3202
|
-
const index = existing.findIndex((item) => item.turn_id ===
|
|
3383
|
+
const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id);
|
|
3203
3384
|
if (index >= 0) {
|
|
3204
|
-
existing[index] =
|
|
3385
|
+
existing[index] = nextTurn;
|
|
3205
3386
|
} else {
|
|
3206
|
-
existing.push(
|
|
3387
|
+
existing.push(nextTurn);
|
|
3207
3388
|
}
|
|
3208
3389
|
return withTurns(state, existing);
|
|
3209
3390
|
}
|
|
@@ -3255,18 +3436,18 @@ function markStreamingTurns(state, turnStatus, toolCallStatus) {
|
|
|
3255
3436
|
// src/session/agent-session.ts
|
|
3256
3437
|
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";
|
|
3257
3438
|
var OOM_KEYWORDS_RE = /(?:\b(?:exit_code|ExitedWith|exited with)|退出码)\D*(?<!\d)137(?!\d)/i;
|
|
3258
|
-
function
|
|
3439
|
+
function isRecord6(value) {
|
|
3259
3440
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3260
3441
|
}
|
|
3261
3442
|
function isOomText(value) {
|
|
3262
3443
|
return typeof value === "string" && OOM_KEYWORDS_RE.test(value);
|
|
3263
3444
|
}
|
|
3264
3445
|
function parseJsonRecord(value) {
|
|
3265
|
-
if (
|
|
3446
|
+
if (isRecord6(value)) return value;
|
|
3266
3447
|
if (typeof value !== "string") return null;
|
|
3267
3448
|
try {
|
|
3268
3449
|
const parsed = JSON.parse(value);
|
|
3269
|
-
return
|
|
3450
|
+
return isRecord6(parsed) ? parsed : null;
|
|
3270
3451
|
} catch {
|
|
3271
3452
|
return null;
|
|
3272
3453
|
}
|
|
@@ -3313,7 +3494,7 @@ function hasChatRunEvent2(events) {
|
|
|
3313
3494
|
);
|
|
3314
3495
|
}
|
|
3315
3496
|
function isUiMetaLike(value) {
|
|
3316
|
-
return
|
|
3497
|
+
return isRecord6(value) && ("resourceHTML" in value || "resourceUri" in value || "resourceURI" in value);
|
|
3317
3498
|
}
|
|
3318
3499
|
var AgentSession = class _AgentSession {
|
|
3319
3500
|
sessionId;
|
|
@@ -3464,7 +3645,7 @@ var AgentSession = class _AgentSession {
|
|
|
3464
3645
|
if (this.getAppContext) {
|
|
3465
3646
|
try {
|
|
3466
3647
|
const rawContext = await this.getAppContext();
|
|
3467
|
-
if (!
|
|
3648
|
+
if (!isRecord6(rawContext)) {
|
|
3468
3649
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3469
3650
|
}
|
|
3470
3651
|
const serialized = JSON.stringify(rawContext);
|
|
@@ -3472,7 +3653,7 @@ var AgentSession = class _AgentSession {
|
|
|
3472
3653
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE\u53EF\u5E8F\u5217\u5316\u7684 JSON \u5BF9\u8C61");
|
|
3473
3654
|
}
|
|
3474
3655
|
const normalized = JSON.parse(serialized);
|
|
3475
|
-
if (!
|
|
3656
|
+
if (!isRecord6(normalized)) {
|
|
3476
3657
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3477
3658
|
}
|
|
3478
3659
|
appContext = normalized;
|
|
@@ -3486,13 +3667,11 @@ var AgentSession = class _AgentSession {
|
|
|
3486
3667
|
let optimisticTurnId = null;
|
|
3487
3668
|
let optimisticAskAnswer;
|
|
3488
3669
|
let previousAskAnswer;
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
});
|
|
3495
|
-
}
|
|
3670
|
+
this.update((state) => {
|
|
3671
|
+
const next = addUserMessage(state, content);
|
|
3672
|
+
optimisticTurnId = next.turns.at(-1)?.turn_id ?? null;
|
|
3673
|
+
return next;
|
|
3674
|
+
});
|
|
3496
3675
|
this.update((s) => ({ ...s, isStreaming: true }));
|
|
3497
3676
|
if (askUserAnswer && typeof askUserAnswer.tool_call_id === "string") {
|
|
3498
3677
|
const { tool_call_id, ...rest } = askUserAnswer;
|
|
@@ -3516,7 +3695,8 @@ var AgentSession = class _AgentSession {
|
|
|
3516
3695
|
thinking_override: options.thinkingOverride,
|
|
3517
3696
|
whatif: options.whatif,
|
|
3518
3697
|
replay_decision: options.replayDecision,
|
|
3519
|
-
app_context: appContext
|
|
3698
|
+
app_context: appContext,
|
|
3699
|
+
kb_ids: options.kbIds && options.kbIds.length > 0 ? options.kbIds : void 0
|
|
3520
3700
|
};
|
|
3521
3701
|
try {
|
|
3522
3702
|
await this.ensureJoined();
|
|
@@ -3855,9 +4035,9 @@ var AgentSession = class _AgentSession {
|
|
|
3855
4035
|
detail,
|
|
3856
4036
|
status,
|
|
3857
4037
|
loopId,
|
|
3858
|
-
metadata:
|
|
4038
|
+
metadata: isRecord6(notification.metadata) ? notification.metadata : void 0
|
|
3859
4039
|
});
|
|
3860
|
-
if (notificationType === "bg:started" &&
|
|
4040
|
+
if (notificationType === "bg:started" && isRecord6(notification.metadata)) {
|
|
3861
4041
|
const taskId = typeof notification.metadata.task_id === "string" ? notification.metadata.task_id : "";
|
|
3862
4042
|
if (taskId) {
|
|
3863
4043
|
this.emitter.emit("backgroundTask", {
|
|
@@ -3987,7 +4167,7 @@ var AgentSession = class _AgentSession {
|
|
|
3987
4167
|
title: ui.title ?? "\u5DE5\u5177\u9884\u89C8"
|
|
3988
4168
|
});
|
|
3989
4169
|
}
|
|
3990
|
-
if (block.type === "system_notification" &&
|
|
4170
|
+
if (block.type === "system_notification" && isRecord6(block.content)) {
|
|
3991
4171
|
this._handleSystemNotification(turn.loop_id, block.content);
|
|
3992
4172
|
}
|
|
3993
4173
|
}
|
|
@@ -4471,7 +4651,7 @@ function resolveAuthToken(options) {
|
|
|
4471
4651
|
|
|
4472
4652
|
// src/version.ts
|
|
4473
4653
|
var SDK_NAME = "agent-client";
|
|
4474
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4654
|
+
var SDK_VERSION = true ? "2610.0.0-beta.21" : "1.1.1";
|
|
4475
4655
|
|
|
4476
4656
|
// src/socket.ts
|
|
4477
4657
|
function withSdkIdentity(auth) {
|
|
@@ -4864,6 +5044,89 @@ function parseXhrHeaders(rawHeaders) {
|
|
|
4864
5044
|
return headers;
|
|
4865
5045
|
}
|
|
4866
5046
|
|
|
5047
|
+
// src/platform-endpoints.ts
|
|
5048
|
+
var PLATFORM_SERVICE_NAMES = [
|
|
5049
|
+
"os",
|
|
5050
|
+
"hub",
|
|
5051
|
+
"agent",
|
|
5052
|
+
"oauth",
|
|
5053
|
+
"llmGateway",
|
|
5054
|
+
"gitea",
|
|
5055
|
+
"tile"
|
|
5056
|
+
];
|
|
5057
|
+
var EMPTY_PLATFORM_ENDPOINTS = Object.freeze({
|
|
5058
|
+
services: Object.freeze({})
|
|
5059
|
+
});
|
|
5060
|
+
function defaultDocumentBaseUrl() {
|
|
5061
|
+
if (typeof document === "undefined") return void 0;
|
|
5062
|
+
if (document.querySelector("base[href]")) return document.baseURI;
|
|
5063
|
+
if (typeof location !== "undefined" && location.origin) return `${location.origin}/`;
|
|
5064
|
+
return document.baseURI;
|
|
5065
|
+
}
|
|
5066
|
+
function isRecord7(value) {
|
|
5067
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5068
|
+
}
|
|
5069
|
+
function normalizeServiceUrl(value) {
|
|
5070
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
5071
|
+
if (value.includes("?") || value.includes("#")) return null;
|
|
5072
|
+
try {
|
|
5073
|
+
const url = new URL(value.trim());
|
|
5074
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
5075
|
+
if (url.username || url.password || url.search || url.hash) return null;
|
|
5076
|
+
return url.toString().replace(/\/$/, "");
|
|
5077
|
+
} catch {
|
|
5078
|
+
return null;
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
function parsePlatformEndpoints(value) {
|
|
5082
|
+
if (!isRecord7(value) || !isRecord7(value.services)) return null;
|
|
5083
|
+
const services = {};
|
|
5084
|
+
for (const name of PLATFORM_SERVICE_NAMES) {
|
|
5085
|
+
if (!(name in value.services)) continue;
|
|
5086
|
+
const url = normalizeServiceUrl(value.services[name]);
|
|
5087
|
+
if (!url) return null;
|
|
5088
|
+
if (name === "agent" && new URL(url).pathname !== "/") return null;
|
|
5089
|
+
services[name] = url;
|
|
5090
|
+
}
|
|
5091
|
+
return { services };
|
|
5092
|
+
}
|
|
5093
|
+
async function loadPlatformEndpoints(options = {}) {
|
|
5094
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
5095
|
+
const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl();
|
|
5096
|
+
if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS;
|
|
5097
|
+
const controller = new AbortController();
|
|
5098
|
+
const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3e3);
|
|
5099
|
+
try {
|
|
5100
|
+
const response = await fetchImpl(new URL("config.json", baseUrl), {
|
|
5101
|
+
cache: "no-store",
|
|
5102
|
+
credentials: "same-origin",
|
|
5103
|
+
headers: { Accept: "application/json" },
|
|
5104
|
+
signal: controller.signal
|
|
5105
|
+
});
|
|
5106
|
+
if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS;
|
|
5107
|
+
return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS;
|
|
5108
|
+
} catch {
|
|
5109
|
+
return EMPTY_PLATFORM_ENDPOINTS;
|
|
5110
|
+
} finally {
|
|
5111
|
+
globalThis.clearTimeout(timeout);
|
|
5112
|
+
}
|
|
5113
|
+
}
|
|
5114
|
+
function resolveServiceUrl(endpoints, name, path = "") {
|
|
5115
|
+
const baseUrl = endpoints.services[name];
|
|
5116
|
+
if (!baseUrl) return null;
|
|
5117
|
+
if (!path) return baseUrl;
|
|
5118
|
+
const pathReference = path.trimStart();
|
|
5119
|
+
if (path.includes("\\") || pathReference.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(pathReference)) {
|
|
5120
|
+
return null;
|
|
5121
|
+
}
|
|
5122
|
+
const base = new URL(`${baseUrl}/`);
|
|
5123
|
+
const target = new URL(path.replace(/^\/+/, ""), base);
|
|
5124
|
+
if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {
|
|
5125
|
+
return null;
|
|
5126
|
+
}
|
|
5127
|
+
return target.toString();
|
|
5128
|
+
}
|
|
5129
|
+
|
|
4867
5130
|
// src/commands/protocol.ts
|
|
4868
5131
|
function isCommandEnvelope(value) {
|
|
4869
5132
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -4968,6 +5231,7 @@ export {
|
|
|
4968
5231
|
BladeClient,
|
|
4969
5232
|
ClientProjectionBuilder,
|
|
4970
5233
|
DEFAULT_REPLAY_SPEED,
|
|
5234
|
+
EMPTY_PLATFORM_ENDPOINTS,
|
|
4971
5235
|
LayoutType,
|
|
4972
5236
|
ModelsResource,
|
|
4973
5237
|
SDK_NAME,
|
|
@@ -4982,9 +5246,11 @@ export {
|
|
|
4982
5246
|
buildMessageContent,
|
|
4983
5247
|
connectEmbedded,
|
|
4984
5248
|
contentPreview,
|
|
5249
|
+
contextProjectionData,
|
|
4985
5250
|
createInitialSessionState,
|
|
4986
5251
|
createSocket,
|
|
4987
5252
|
extractTextAttachments,
|
|
5253
|
+
getContextDisplayState,
|
|
4988
5254
|
getFileParts,
|
|
4989
5255
|
getImageParts,
|
|
4990
5256
|
getTextContent,
|
|
@@ -4993,7 +5259,10 @@ export {
|
|
|
4993
5259
|
isHiddenInternalMessage,
|
|
4994
5260
|
isInboundEnvelope,
|
|
4995
5261
|
latestPostChatFollowup,
|
|
5262
|
+
loadPlatformEndpoints,
|
|
4996
5263
|
normalizeMessageContent,
|
|
5264
|
+
reconcileOptimisticUserTurns,
|
|
5265
|
+
resolveServiceUrl,
|
|
4997
5266
|
toReplaySnapshot,
|
|
4998
5267
|
transformSlashCommand
|
|
4999
5268
|
};
|