@blade-hq/agent-client 2610.0.0-beta.3 → 2610.0.0-beta.30
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 +69 -4
- package/dist/blade-client.d.ts +2 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +515 -72
- package/dist/index.js.map +1 -1
- package/dist/platform-endpoints.d.ts +14 -0
- package/dist/resources/computers.d.ts +63 -0
- package/dist/resources/models.d.ts +2 -0
- package/dist/resources/sessions.d.ts +3 -1
- package/dist/schemas/context.d.ts +34 -0
- package/dist/schemas/event.d.ts +9 -0
- package/dist/schemas/message-utils.d.ts +2 -0
- package/dist/schemas/message.d.ts +5 -0
- package/dist/schemas/projection.d.ts +14 -1
- package/dist/schemas/session.d.ts +3 -1
- package/dist/session/agent-session.d.ts +3 -1
- 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 +13 -4
- package/package.json +1 -1
- package/public-api.md +193 -4
package/dist/index.js
CHANGED
|
@@ -352,8 +352,7 @@ var HeadlessResource = class {
|
|
|
352
352
|
socket.on("system:error", onSystemError);
|
|
353
353
|
socket.emit("session:subscribe", {
|
|
354
354
|
session_id,
|
|
355
|
-
event_format: "raw"
|
|
356
|
-
stream_tokens: this.client.options.streamTokens !== false
|
|
355
|
+
event_format: "raw"
|
|
357
356
|
});
|
|
358
357
|
socket.emit(
|
|
359
358
|
"chat:send",
|
|
@@ -425,6 +424,50 @@ function ensureSocketConnected(socket, timeoutMs, detail) {
|
|
|
425
424
|
});
|
|
426
425
|
}
|
|
427
426
|
|
|
427
|
+
// src/resources/computers.ts
|
|
428
|
+
function computerState(computer) {
|
|
429
|
+
if (computer.is_primary) return "primary";
|
|
430
|
+
if (computer.enabled) return "enabled";
|
|
431
|
+
return computer.online ? "idle" : "offline";
|
|
432
|
+
}
|
|
433
|
+
function canToggleComputer(computer) {
|
|
434
|
+
return !computer.is_primary;
|
|
435
|
+
}
|
|
436
|
+
function sortComputers(computers) {
|
|
437
|
+
return [...computers].sort((a, b) => {
|
|
438
|
+
if (a.enabled !== b.enabled) return a.enabled ? -1 : 1;
|
|
439
|
+
if (a.online !== b.online) return a.online ? -1 : 1;
|
|
440
|
+
return a.label.localeCompare(b.label);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
var ComputersResource = class {
|
|
444
|
+
constructor(client) {
|
|
445
|
+
this.client = client;
|
|
446
|
+
}
|
|
447
|
+
client;
|
|
448
|
+
/**
|
|
449
|
+
* 列出当前用户的全部电脑,带上"在不在线"和"这次会话能不能用"。
|
|
450
|
+
* 服务端只查库,电脑离线时同样返回,所以拿得到"它离线了"这个结论。
|
|
451
|
+
*/
|
|
452
|
+
list(sessionId) {
|
|
453
|
+
return this.client.json(
|
|
454
|
+
"GET",
|
|
455
|
+
`/api/sessions/${encodeURIComponent(sessionId)}/computers`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* 启动或停止一台电脑。只改这次会话的可用范围,不会碰远程机器,
|
|
460
|
+
* 电脑离线时同样能登记,等它上线就直接可用。
|
|
461
|
+
*/
|
|
462
|
+
setEnabled(sessionId, computer, enabled) {
|
|
463
|
+
return this.client.json(
|
|
464
|
+
"PUT",
|
|
465
|
+
`/api/sessions/${encodeURIComponent(sessionId)}/computers/${encodeURIComponent(computer)}/enabled`,
|
|
466
|
+
{ enabled }
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
428
471
|
// src/resources/models.ts
|
|
429
472
|
var ModelsResource = class {
|
|
430
473
|
constructor(client) {
|
|
@@ -473,6 +516,7 @@ var SessionInfo = type({
|
|
|
473
516
|
"disable_tools?": "string[]",
|
|
474
517
|
"runtime_type?": "string | null",
|
|
475
518
|
"daemon_id?": "string | null",
|
|
519
|
+
"agent_runtime_id?": "string | null",
|
|
476
520
|
"workspace_path?": "string | null",
|
|
477
521
|
"match?": "unknown"
|
|
478
522
|
});
|
|
@@ -1023,6 +1067,91 @@ function toolStatusFromResult(result) {
|
|
|
1023
1067
|
return inferToolStatus(text);
|
|
1024
1068
|
}
|
|
1025
1069
|
|
|
1070
|
+
// src/schemas/context.ts
|
|
1071
|
+
var BUILTIN_CONTEXT_TITLES = {
|
|
1072
|
+
"agent-instructions": "\u9879\u76EE\u8BF4\u660E",
|
|
1073
|
+
"skill-catalog": "\u53EF\u7528\u80FD\u529B",
|
|
1074
|
+
"runtime-context": "\u5F53\u524D\u5DE5\u4F5C\u73AF\u5883",
|
|
1075
|
+
"workspace-context": "\u5F53\u524D\u5DE5\u4F5C\u533A\u73AF\u5883"
|
|
1076
|
+
};
|
|
1077
|
+
var BUILTIN_CONTEXT_DETAILS = {
|
|
1078
|
+
"agent-instructions": "\u8FD9\u4E9B\u8BF4\u660E\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u7406\u89E3\u5F53\u524D\u9879\u76EE\u548C\u5DE5\u4F5C\u8981\u6C42\u3002",
|
|
1079
|
+
"skill-catalog": "\u8FD9\u4E9B\u80FD\u529B\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u9009\u62E9\u5408\u9002\u7684\u65B9\u5F0F\u5B8C\u6210\u4EFB\u52A1\u3002",
|
|
1080
|
+
"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",
|
|
1081
|
+
"workspace-context": "\u8FD9\u4E9B\u4FE1\u606F\u4F1A\u5E2E\u52A9\u667A\u80FD\u4F53\u4E86\u89E3\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3001\u6587\u4EF6\u548C\u8FD0\u884C\u73AF\u5883\u3002"
|
|
1082
|
+
};
|
|
1083
|
+
function nonEmptyString(value) {
|
|
1084
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1085
|
+
}
|
|
1086
|
+
function contextProjectionData(fields) {
|
|
1087
|
+
const contextKind = nonEmptyString(fields.context_kind);
|
|
1088
|
+
const contextKey = nonEmptyString(fields.context_key);
|
|
1089
|
+
const contextName = nonEmptyString(fields.context_name);
|
|
1090
|
+
const contextRevision = nonEmptyString(fields.context_revision);
|
|
1091
|
+
if (!contextKind || !contextKey || !contextName || !contextRevision || typeof fields.context_order !== "number" || !Number.isFinite(fields.context_order) || !fields.context_action) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
context_kind: contextKind,
|
|
1096
|
+
context_key: contextKey,
|
|
1097
|
+
context_name: contextName,
|
|
1098
|
+
context_order: fields.context_order,
|
|
1099
|
+
context_action: fields.context_action,
|
|
1100
|
+
context_revision: contextRevision,
|
|
1101
|
+
display_title: nonEmptyString(fields.display_title),
|
|
1102
|
+
display_summary: nonEmptyString(fields.display_summary),
|
|
1103
|
+
sources: Array.isArray(fields.sources) ? fields.sources : []
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function getContextDisplayState(context) {
|
|
1107
|
+
const title = BUILTIN_CONTEXT_TITLES[context.context_kind] ?? nonEmptyString(context.display_title) ?? "\u5BF9\u8BDD\u80CC\u666F";
|
|
1108
|
+
const isRemoved = context.context_action === "removed";
|
|
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
|
+
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
|
+
return { title, summary, detail, isRemoved };
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// src/shared/projection/context.ts
|
|
1115
|
+
function isRecord2(value) {
|
|
1116
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1117
|
+
}
|
|
1118
|
+
function buildContextTurn(entry, sequence) {
|
|
1119
|
+
if (entry.kind !== "context" || !isRecord2(entry.source) || !isRecord2(entry.data)) {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
const display = isRecord2(entry.data.display) ? entry.data.display : {};
|
|
1123
|
+
const message = isRecord2(entry.message) ? entry.message : {};
|
|
1124
|
+
const context = contextProjectionData({
|
|
1125
|
+
context_kind: typeof entry.source.kind === "string" ? entry.source.kind : null,
|
|
1126
|
+
context_key: typeof entry.source.key === "string" ? entry.source.key : null,
|
|
1127
|
+
context_name: typeof entry.data.contribution_name === "string" ? entry.data.contribution_name : null,
|
|
1128
|
+
context_order: typeof entry.data.order === "number" ? entry.data.order : null,
|
|
1129
|
+
context_action: entry.data.action === "published" || entry.data.action === "retained" || entry.data.action === "removed" ? entry.data.action : null,
|
|
1130
|
+
context_revision: typeof entry.data.revision === "string" ? entry.data.revision : null,
|
|
1131
|
+
display_title: typeof display.title === "string" ? display.title : null,
|
|
1132
|
+
display_summary: typeof display.summary === "string" ? display.summary : null,
|
|
1133
|
+
sources: Array.isArray(display.sources) ? display.sources.filter(isRecord2) : []
|
|
1134
|
+
});
|
|
1135
|
+
if (!context) return null;
|
|
1136
|
+
const turnId = typeof entry.id === "string" && entry.id ? entry.id : `context-${sequence}`;
|
|
1137
|
+
return {
|
|
1138
|
+
id: turnId,
|
|
1139
|
+
sequence,
|
|
1140
|
+
turn_id: turnId,
|
|
1141
|
+
loop_id: typeof entry.loop_name === "string" && entry.loop_name ? entry.loop_name : "root",
|
|
1142
|
+
kind: "context",
|
|
1143
|
+
role: "system",
|
|
1144
|
+
status: "completed",
|
|
1145
|
+
blocks: [],
|
|
1146
|
+
tool_calls: [],
|
|
1147
|
+
model: null,
|
|
1148
|
+
usage: null,
|
|
1149
|
+
duration_ms: 0,
|
|
1150
|
+
context_content: Object.hasOwn(message, "content") ? message.content : null,
|
|
1151
|
+
...context
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1026
1155
|
// src/shared/projection/builder.ts
|
|
1027
1156
|
function hasChatRunEvent(events) {
|
|
1028
1157
|
return events.some(
|
|
@@ -1058,7 +1187,8 @@ function completedResponseText(content) {
|
|
|
1058
1187
|
).filter((part) => part.type === "text").map((part) => String(part.text ?? "")).join("");
|
|
1059
1188
|
}
|
|
1060
1189
|
function replaceTextContent(state, content) {
|
|
1061
|
-
|
|
1190
|
+
const currentContent = state.blocks.filter((block) => block.type === "text").map((block) => String(block.content ?? "")).join("");
|
|
1191
|
+
if (currentContent === content) return;
|
|
1062
1192
|
const replacement = { type: "text", content };
|
|
1063
1193
|
const blocks = [];
|
|
1064
1194
|
let inserted = false;
|
|
@@ -1078,6 +1208,31 @@ function replaceTextContent(state, content) {
|
|
|
1078
1208
|
}
|
|
1079
1209
|
state.blocks = blocks;
|
|
1080
1210
|
}
|
|
1211
|
+
function applyResponseBlockOrder(state, value) {
|
|
1212
|
+
if (!Array.isArray(value)) return false;
|
|
1213
|
+
const ordered = [];
|
|
1214
|
+
for (const item of value) {
|
|
1215
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) continue;
|
|
1216
|
+
const block = item;
|
|
1217
|
+
if (block.type === "text" || block.type === "thinking") {
|
|
1218
|
+
const content = String(block[block.type] ?? "");
|
|
1219
|
+
if (content) ordered.push({ type: block.type, content });
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
if (block.type !== "tool_call") continue;
|
|
1223
|
+
const toolCallId = String(block.id ?? "");
|
|
1224
|
+
const toolBlock = state.blocks.find(
|
|
1225
|
+
(candidate) => candidate.type === "tool_use" && candidate.tool_call_id === toolCallId
|
|
1226
|
+
);
|
|
1227
|
+
if (toolBlock) ordered.push(toolBlock);
|
|
1228
|
+
}
|
|
1229
|
+
if (ordered.length === 0 && value.length > 0) return false;
|
|
1230
|
+
const unrelatedBlocks = state.blocks.filter(
|
|
1231
|
+
(block) => block.type !== "text" && block.type !== "thinking" && block.type !== "tool_use"
|
|
1232
|
+
);
|
|
1233
|
+
state.blocks = [...ordered, ...unrelatedBlocks];
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1081
1236
|
var ClientProjectionBuilder = class {
|
|
1082
1237
|
activeTurns = /* @__PURE__ */ new Map();
|
|
1083
1238
|
lastTurnIds = /* @__PURE__ */ new Map();
|
|
@@ -1117,6 +1272,8 @@ var ClientProjectionBuilder = class {
|
|
|
1117
1272
|
return this.onMemoryInject(loopId, payload);
|
|
1118
1273
|
case "memory:inject:none":
|
|
1119
1274
|
return null;
|
|
1275
|
+
case "context:entry":
|
|
1276
|
+
return this.onContextEntry(payload);
|
|
1120
1277
|
case "loop:turn":
|
|
1121
1278
|
return this.onLoopTurn(loopId, payload);
|
|
1122
1279
|
case "mode:change":
|
|
@@ -1165,6 +1322,8 @@ var ClientProjectionBuilder = class {
|
|
|
1165
1322
|
return this.syncPatch(state);
|
|
1166
1323
|
case "llm:tool_call:created":
|
|
1167
1324
|
return this.onToolCallCreated(state, payload);
|
|
1325
|
+
case "llm:tool_call:arguments:delta":
|
|
1326
|
+
return this.onToolCallArgumentsDelta(state, payload);
|
|
1168
1327
|
case "llm:response:done":
|
|
1169
1328
|
return this.onResponseDone(state, loopId, payload);
|
|
1170
1329
|
case "tool:result:delta":
|
|
@@ -1232,6 +1391,11 @@ var ClientProjectionBuilder = class {
|
|
|
1232
1391
|
}
|
|
1233
1392
|
return null;
|
|
1234
1393
|
}
|
|
1394
|
+
onContextEntry(payload) {
|
|
1395
|
+
if (!isRecord3(payload.entry)) return null;
|
|
1396
|
+
const turn = buildContextTurn(payload.entry, this.nextSeq());
|
|
1397
|
+
return turn ? [{ kind: "upsert", turn }] : null;
|
|
1398
|
+
}
|
|
1235
1399
|
onLoopTurn(loopId, payload) {
|
|
1236
1400
|
let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`));
|
|
1237
1401
|
let memoryRefs = null;
|
|
@@ -1288,11 +1452,11 @@ var ClientProjectionBuilder = class {
|
|
|
1288
1452
|
loopId,
|
|
1289
1453
|
toolCallId: optStr(payload.tool_call_id) ?? void 0,
|
|
1290
1454
|
toolName: toolNameFromPayload(payload) ?? void 0,
|
|
1291
|
-
workspacePath:
|
|
1455
|
+
workspacePath: isRecord3(payload.workspace_change) ? optStr(payload.workspace_change.to) ?? void 0 : void 0
|
|
1292
1456
|
}
|
|
1293
1457
|
];
|
|
1294
1458
|
const change = payload.workspace_change;
|
|
1295
|
-
if (
|
|
1459
|
+
if (isRecord3(change)) {
|
|
1296
1460
|
const source = optStr(change.source) ?? "";
|
|
1297
1461
|
const projectName = optStr(change.project_name) ?? "";
|
|
1298
1462
|
const fromPath = optStr(change.from) ?? "";
|
|
@@ -1430,13 +1594,7 @@ var ClientProjectionBuilder = class {
|
|
|
1430
1594
|
}
|
|
1431
1595
|
onToolCallCreated(state, payload) {
|
|
1432
1596
|
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;
|
|
1597
|
+
return this.onToolCallArgumentsDelta(state, payload);
|
|
1440
1598
|
}
|
|
1441
1599
|
const toolCallId = String(payload.id ?? "");
|
|
1442
1600
|
const toolName = toolNameFromPayload(payload);
|
|
@@ -1445,6 +1603,13 @@ var ClientProjectionBuilder = class {
|
|
|
1445
1603
|
upsertToolCall(state, toolCallId, toolName, displayName, args);
|
|
1446
1604
|
return this.syncPatch(state);
|
|
1447
1605
|
}
|
|
1606
|
+
onToolCallArgumentsDelta(state, payload) {
|
|
1607
|
+
const delta = String(payload.arguments_delta ?? "");
|
|
1608
|
+
const toolCallId = String(payload.id ?? "");
|
|
1609
|
+
if (!delta || !toolCallId) return null;
|
|
1610
|
+
appendToolCallArguments(state, toolCallId, delta);
|
|
1611
|
+
return this.syncPatch(state);
|
|
1612
|
+
}
|
|
1448
1613
|
onResponseDone(state, loopId, payload) {
|
|
1449
1614
|
state.responseDone = true;
|
|
1450
1615
|
const model = optStr(payload.model);
|
|
@@ -1452,9 +1617,6 @@ var ClientProjectionBuilder = class {
|
|
|
1452
1617
|
if (typeof payload.usage === "object" && payload.usage !== null) {
|
|
1453
1618
|
state.usage = { ...payload.usage };
|
|
1454
1619
|
}
|
|
1455
|
-
if ("content" in payload) {
|
|
1456
|
-
replaceTextContent(state, completedResponseText(payload.content));
|
|
1457
|
-
}
|
|
1458
1620
|
const toolCalls = payload.tool_calls;
|
|
1459
1621
|
if (Array.isArray(toolCalls)) {
|
|
1460
1622
|
for (const raw of toolCalls) {
|
|
@@ -1472,7 +1634,13 @@ var ClientProjectionBuilder = class {
|
|
|
1472
1634
|
);
|
|
1473
1635
|
}
|
|
1474
1636
|
}
|
|
1475
|
-
if (state.
|
|
1637
|
+
if (!applyResponseBlockOrder(state, payload.response_blocks) && "content" in payload) {
|
|
1638
|
+
replaceTextContent(state, completedResponseText(payload.content));
|
|
1639
|
+
}
|
|
1640
|
+
const isNativeProviderResponse = typeof payload.provider === "string" && payload.provider !== "";
|
|
1641
|
+
if (state.toolCalls.length === 0 || isNativeProviderResponse && state.toolCalls.every(
|
|
1642
|
+
(toolCall) => toolCall.status !== "pending" && toolCall.status !== "awaiting_answer"
|
|
1643
|
+
)) {
|
|
1476
1644
|
return this.finalize(loopId, "completed");
|
|
1477
1645
|
}
|
|
1478
1646
|
return this.syncPatch(state);
|
|
@@ -1486,7 +1654,8 @@ var ClientProjectionBuilder = class {
|
|
|
1486
1654
|
const durationMs = typeof rawDuration === "number" && rawDuration >= 0 ? Math.round(rawDuration) : null;
|
|
1487
1655
|
const sl = sourceLoopFor(state.loopId, this.loopDescriptions);
|
|
1488
1656
|
applyToolResult(state, toolCallId, content, status, durationMs, sl);
|
|
1489
|
-
|
|
1657
|
+
const isNativeProviderResult = typeof payload.provider === "string" && payload.provider !== "";
|
|
1658
|
+
if (!isNativeProviderResult && this.shouldFinalizeAfterToolResults(state)) {
|
|
1490
1659
|
return this.finalize(loopId, "completed");
|
|
1491
1660
|
}
|
|
1492
1661
|
return this.syncPatch(state);
|
|
@@ -1527,6 +1696,11 @@ var ClientProjectionBuilder = class {
|
|
|
1527
1696
|
const toolName = String(payload.tool_name ?? "");
|
|
1528
1697
|
const displayName = this.displayNameResolver(toolName);
|
|
1529
1698
|
upsertToolCall(state, toolCallId, toolName, displayName, "");
|
|
1699
|
+
const relatedToolCallId = String(payload.related_tool_call_id ?? "");
|
|
1700
|
+
if (relatedToolCallId && relatedToolCallId !== toolCallId) {
|
|
1701
|
+
const related = state.toolCalls.find((toolCall) => toolCall.id === relatedToolCallId);
|
|
1702
|
+
if (related) related.status = "awaiting_answer";
|
|
1703
|
+
}
|
|
1530
1704
|
return this.syncPatch(state);
|
|
1531
1705
|
}
|
|
1532
1706
|
onChildPause(state, loopId, payload) {
|
|
@@ -1754,7 +1928,7 @@ var ClientProjectionBuilder = class {
|
|
|
1754
1928
|
return `${prefix}:${this.syntheticCounter}:${hex}`;
|
|
1755
1929
|
}
|
|
1756
1930
|
};
|
|
1757
|
-
function
|
|
1931
|
+
function isRecord3(value) {
|
|
1758
1932
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1759
1933
|
}
|
|
1760
1934
|
function optStr(value) {
|
|
@@ -1783,6 +1957,7 @@ function projectHistory(entries) {
|
|
|
1783
1957
|
const latestAssistantByLoop = /* @__PURE__ */ new Map();
|
|
1784
1958
|
const pendingChildPauses = /* @__PURE__ */ new Map();
|
|
1785
1959
|
const answeredToolCallIds = /* @__PURE__ */ new Set();
|
|
1960
|
+
const nativeToolTurns = /* @__PURE__ */ new Set();
|
|
1786
1961
|
let latestRootMessage = null;
|
|
1787
1962
|
let latestRootAssistant = null;
|
|
1788
1963
|
let sequence = 0;
|
|
@@ -1790,7 +1965,7 @@ function projectHistory(entries) {
|
|
|
1790
1965
|
const kind = String(entry.kind ?? "");
|
|
1791
1966
|
const loopId = String(entry.loop_name ?? "root");
|
|
1792
1967
|
const id = String(entry.id ?? `history-${sequence + 1}`);
|
|
1793
|
-
if (kind === "post_chat_followup" &&
|
|
1968
|
+
if (kind === "post_chat_followup" && isRecord4(entry.data)) {
|
|
1794
1969
|
const assistantEntryId = String(entry.data.assistant_entry_id ?? "");
|
|
1795
1970
|
if (latestRootMessage?.role === "assistant" && latestRootMessage.turn_id === assistantEntryId) {
|
|
1796
1971
|
const followup = normalizePostChatFollowup(entry.data, assistantEntryId);
|
|
@@ -1798,7 +1973,15 @@ function projectHistory(entries) {
|
|
|
1798
1973
|
}
|
|
1799
1974
|
continue;
|
|
1800
1975
|
}
|
|
1801
|
-
if (kind === "
|
|
1976
|
+
if (kind === "context") {
|
|
1977
|
+
const turn = buildContextTurn(entry, sequence + 1);
|
|
1978
|
+
if (turn) {
|
|
1979
|
+
sequence += 1;
|
|
1980
|
+
turns.push(turn);
|
|
1981
|
+
}
|
|
1982
|
+
continue;
|
|
1983
|
+
}
|
|
1984
|
+
if (kind === "message" && isRecord4(entry.message)) {
|
|
1802
1985
|
const message = entry.message;
|
|
1803
1986
|
const role = String(message.role ?? "");
|
|
1804
1987
|
if (role === "tool") {
|
|
@@ -1830,14 +2013,31 @@ function projectHistory(entries) {
|
|
|
1830
2013
|
blocks,
|
|
1831
2014
|
tool_calls: toolCalls,
|
|
1832
2015
|
model: stringOrNull(message.model),
|
|
1833
|
-
usage:
|
|
2016
|
+
usage: isRecord4(message._usage) ? { ...message._usage } : null,
|
|
1834
2017
|
duration_ms: numberOrZero(message._duration_ms),
|
|
1835
2018
|
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
|
|
1836
2019
|
};
|
|
2020
|
+
const isNativeToolEntry = role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.some(
|
|
2021
|
+
(toolCall) => isRecord4(toolCall) && typeof toolCall.provider === "string"
|
|
2022
|
+
);
|
|
2023
|
+
const previousTurn = turns[turns.length - 1];
|
|
2024
|
+
if (role === "assistant" && previousTurn?.role === "assistant" && previousTurn.loop_id === loopId && nativeToolTurns.has(previousTurn)) {
|
|
2025
|
+
previousTurn.blocks.push(...turn.blocks);
|
|
2026
|
+
previousTurn.tool_calls.push(...turn.tool_calls);
|
|
2027
|
+
previousTurn.status = turn.status;
|
|
2028
|
+
previousTurn.model = turn.model ?? previousTurn.model;
|
|
2029
|
+
previousTurn.usage = turn.usage ?? previousTurn.usage;
|
|
2030
|
+
previousTurn.duration_ms = turn.duration_ms || previousTurn.duration_ms;
|
|
2031
|
+
if (turn.started_at) previousTurn.started_at = turn.started_at;
|
|
2032
|
+
if (loopId === "root") latestRootMessage = previousTurn;
|
|
2033
|
+
latestAssistantByLoop.set(loopId, previousTurn);
|
|
2034
|
+
continue;
|
|
2035
|
+
}
|
|
1837
2036
|
if (loopId === "root" && (role === "user" || role === "assistant")) {
|
|
1838
2037
|
latestRootMessage = turn;
|
|
1839
2038
|
}
|
|
1840
2039
|
turns.push(turn);
|
|
2040
|
+
if (isNativeToolEntry) nativeToolTurns.add(turn);
|
|
1841
2041
|
if (role === "assistant") latestAssistantByLoop.set(loopId, turn);
|
|
1842
2042
|
if (loopId === "root") {
|
|
1843
2043
|
if (role === "assistant") latestRootAssistant = turn;
|
|
@@ -1846,10 +2046,25 @@ function projectHistory(entries) {
|
|
|
1846
2046
|
for (const toolCall of toolCalls) toolOwners.set(toolCall.id, turn);
|
|
1847
2047
|
continue;
|
|
1848
2048
|
}
|
|
2049
|
+
if (kind === "tool_result") {
|
|
2050
|
+
const data = entry.data ?? {};
|
|
2051
|
+
const toolCallId = String(data.tool_call_id ?? "");
|
|
2052
|
+
const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId);
|
|
2053
|
+
if (owner && toolCallId) {
|
|
2054
|
+
const rawContent = data.content;
|
|
2055
|
+
const content = typeof rawContent === "string" ? rawContent : Array.isArray(rawContent) ? rawContent : String(rawContent ?? "");
|
|
2056
|
+
const status = data.is_error === true ? "error" : inferToolStatus(typeof content === "string" ? content : JSON.stringify(content));
|
|
2057
|
+
setToolCallStatus(owner, toolCallId, status, content, null);
|
|
2058
|
+
if (!owner.blocks.some((block) => block.type === "tool_result" && block.tool_call_id === toolCallId)) {
|
|
2059
|
+
owner.blocks.push({ type: "tool_result", content, tool_call_id: toolCallId });
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
continue;
|
|
2063
|
+
}
|
|
1849
2064
|
if (kind === "mode_change") {
|
|
1850
2065
|
turns.push(markerTurn(id, ++sequence, loopId, "mode_change", entry.data ?? {}));
|
|
1851
2066
|
} else if (kind === "workspace_change") {
|
|
1852
|
-
const change =
|
|
2067
|
+
const change = isRecord4(entry.data) ? entry.data : {};
|
|
1853
2068
|
const source = stringOrNull(change.source) ?? "";
|
|
1854
2069
|
const projectName = stringOrNull(change.project_name) ?? "";
|
|
1855
2070
|
const fromPath = stringOrNull(change.from) ?? "";
|
|
@@ -1890,7 +2105,7 @@ function projectHistory(entries) {
|
|
|
1890
2105
|
} else if (kind === "compaction" || kind === "tool_result_archive") {
|
|
1891
2106
|
const data = entry.data ?? {};
|
|
1892
2107
|
const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`);
|
|
1893
|
-
let content =
|
|
2108
|
+
let content = isRecord4(entry.message) ? entry.message.content : void 0;
|
|
1894
2109
|
if (kind === "tool_result_archive") {
|
|
1895
2110
|
const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0;
|
|
1896
2111
|
content = `<compaction-summary>
|
|
@@ -1905,11 +2120,11 @@ function projectHistory(entries) {
|
|
|
1905
2120
|
);
|
|
1906
2121
|
} else if (kind === "child_pause") {
|
|
1907
2122
|
const data = entry.data ?? {};
|
|
1908
|
-
const sourceLoop =
|
|
2123
|
+
const sourceLoop = isRecord4(data.source_loop) ? data.source_loop : {};
|
|
1909
2124
|
const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? "");
|
|
1910
2125
|
const childToolCallId = String(data.child_pause_tool_call_id ?? "");
|
|
1911
2126
|
const parentToolCallId = String(data.parent_fork_tool_call_id ?? "");
|
|
1912
|
-
const pauseToolData =
|
|
2127
|
+
const pauseToolData = isRecord4(data.pause_tool_data) ? data.pause_tool_data : {};
|
|
1913
2128
|
const description = String(sourceLoop.description ?? "");
|
|
1914
2129
|
applyAskUserPauseToTurn(
|
|
1915
2130
|
latestAssistantByLoop.get(childLoopId),
|
|
@@ -1997,15 +2212,15 @@ function parseToolArguments(value) {
|
|
|
1997
2212
|
if (!value) return {};
|
|
1998
2213
|
try {
|
|
1999
2214
|
const parsed = JSON.parse(value);
|
|
2000
|
-
return
|
|
2215
|
+
return isRecord4(parsed) ? parsed : {};
|
|
2001
2216
|
} catch {
|
|
2002
2217
|
return {};
|
|
2003
2218
|
}
|
|
2004
2219
|
}
|
|
2005
2220
|
function buildToolCalls(value) {
|
|
2006
2221
|
if (!Array.isArray(value)) return [];
|
|
2007
|
-
return value.filter(
|
|
2008
|
-
const fn =
|
|
2222
|
+
return value.filter(isRecord4).map((raw) => {
|
|
2223
|
+
const fn = isRecord4(raw.function) ? raw.function : {};
|
|
2009
2224
|
const name = String(fn.name ?? "");
|
|
2010
2225
|
return {
|
|
2011
2226
|
id: String(raw.id ?? ""),
|
|
@@ -2021,23 +2236,40 @@ function buildBlocks(message, toolCalls) {
|
|
|
2021
2236
|
const displayContent = message.role === "user" ? message._display_content : void 0;
|
|
2022
2237
|
const stored = message._blocks;
|
|
2023
2238
|
const blocks = [];
|
|
2239
|
+
const storedToolCallIds = /* @__PURE__ */ new Set();
|
|
2024
2240
|
if (displayContent !== void 0) {
|
|
2025
2241
|
blocks.push({ type: "text", content: displayContent });
|
|
2026
2242
|
} else if (Array.isArray(stored)) {
|
|
2027
2243
|
for (const raw of stored) {
|
|
2028
|
-
if (!
|
|
2244
|
+
if (!isRecord4(raw)) continue;
|
|
2029
2245
|
const type3 = String(raw.type ?? "");
|
|
2030
2246
|
if (type3 === "thinking") blocks.push({ type: type3, content: raw.thinking ?? raw.content ?? "" });
|
|
2031
2247
|
if (type3 === "text") blocks.push({ type: type3, content: raw.text ?? raw.content ?? "" });
|
|
2248
|
+
if (type3 === "tool_call") {
|
|
2249
|
+
const toolCallId = String(raw.id ?? "");
|
|
2250
|
+
const toolCall = toolCalls.find((candidate) => candidate.id === toolCallId);
|
|
2251
|
+
if (!toolCall) continue;
|
|
2252
|
+
storedToolCallIds.add(toolCallId);
|
|
2253
|
+
blocks.push({
|
|
2254
|
+
type: "tool_use",
|
|
2255
|
+
content: toolCall.arguments,
|
|
2256
|
+
tool_call_id: toolCall.id,
|
|
2257
|
+
tool_name: toolCall.tool_name,
|
|
2258
|
+
display_name: toolCall.display_name
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2032
2261
|
}
|
|
2033
2262
|
} else if (message.content !== void 0 && message.content !== "") {
|
|
2034
2263
|
blocks.push({ type: "text", content: message.content });
|
|
2035
2264
|
}
|
|
2036
2265
|
for (const toolCall of toolCalls) {
|
|
2266
|
+
if (storedToolCallIds.has(toolCall.id)) continue;
|
|
2037
2267
|
blocks.push({
|
|
2038
2268
|
type: "tool_use",
|
|
2039
|
-
content:
|
|
2040
|
-
tool_call_id: toolCall.id
|
|
2269
|
+
content: toolCall.arguments,
|
|
2270
|
+
tool_call_id: toolCall.id,
|
|
2271
|
+
tool_name: toolCall.tool_name,
|
|
2272
|
+
display_name: toolCall.display_name
|
|
2041
2273
|
});
|
|
2042
2274
|
}
|
|
2043
2275
|
return blocks;
|
|
@@ -2058,7 +2290,7 @@ function markerTurn(id, sequence, loopId, type3, content, toolCallId = null) {
|
|
|
2058
2290
|
duration_ms: 0
|
|
2059
2291
|
};
|
|
2060
2292
|
}
|
|
2061
|
-
function
|
|
2293
|
+
function isRecord4(value) {
|
|
2062
2294
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2063
2295
|
}
|
|
2064
2296
|
function stringOrNull(value) {
|
|
@@ -2094,7 +2326,8 @@ function toCreateSessionPayload(request) {
|
|
|
2094
2326
|
solution_snapshot_session_id: request.solution_snapshot_session_id ?? null,
|
|
2095
2327
|
compaction_ratio: request.compaction_ratio ?? null,
|
|
2096
2328
|
...request.runtime_type ? { runtime_type: request.runtime_type } : {},
|
|
2097
|
-
...request.daemon_id ? { daemon_id: request.daemon_id } : {}
|
|
2329
|
+
...request.daemon_id ? { daemon_id: request.daemon_id } : {},
|
|
2330
|
+
...request.agent_runtime_id ? { agent_runtime_id: request.agent_runtime_id } : {}
|
|
2098
2331
|
};
|
|
2099
2332
|
}
|
|
2100
2333
|
var builtinSolutionIds = /* @__PURE__ */ new Set([
|
|
@@ -2708,6 +2941,36 @@ var LEGACY_FORK_CONTEXT_MARKERS = [
|
|
|
2708
2941
|
"\u53EF\u901A\u8FC7 `read_file` \u8BFB\u53D6\u3002",
|
|
2709
2942
|
"# \u4F60\u7684\u4EFB\u52A1"
|
|
2710
2943
|
];
|
|
2944
|
+
var INTERNAL_CHAT_ERROR_PATTERNS = [
|
|
2945
|
+
/\b(?:ENOENT|EACCES|EPERM)\b/i,
|
|
2946
|
+
/\[(?:Errno -?\d+|WinError \d+)\]/i,
|
|
2947
|
+
/\b(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|ENOTFOUND|EAI_AGAIN)\b/i,
|
|
2948
|
+
/\b(?:Connection refused|Connection reset by peer|All connection attempts failed|getaddrinfo failed)\b/i,
|
|
2949
|
+
/(?:^|[\s("'`])\/(?:root|home|Users|tmp|var|opt|etc)\//,
|
|
2950
|
+
/[A-Za-z]:\\(?:Users|Windows|Program Files|AppData)\\/i,
|
|
2951
|
+
/(?:^|\n)Traceback \(most recent call last\):/,
|
|
2952
|
+
/(?:^|\n)\s*at\s+\S+(?:\s+\(|:\d+:\d+)/,
|
|
2953
|
+
/(?:^|\n)File "[^"]+", line \d+/
|
|
2954
|
+
];
|
|
2955
|
+
var SAFE_CHAT_ERROR_PREFIXES = [
|
|
2956
|
+
"\u6C99\u76D2\u8FD0\u884C\u73AF\u5883\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
2957
|
+
"\u6A21\u578B\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u6A21\u578B\u914D\u7F6E\u540E\u91CD\u8BD5\u3002"
|
|
2958
|
+
];
|
|
2959
|
+
var GENERIC_CHAT_ERROR = "\u6D88\u606F\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002";
|
|
2960
|
+
function chatErrorForDisplay(message, developer = false) {
|
|
2961
|
+
const normalized = message.trim();
|
|
2962
|
+
if (!developer) {
|
|
2963
|
+
const safePrefix = SAFE_CHAT_ERROR_PREFIXES.find((prefix) => normalized.startsWith(prefix));
|
|
2964
|
+
if (safePrefix) return safePrefix;
|
|
2965
|
+
}
|
|
2966
|
+
if (!developer && /no source matches this model/i.test(normalized)) {
|
|
2967
|
+
return "\u5F53\u524D\u6A21\u578B\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u91CD\u65B0\u9009\u62E9\u6A21\u578B\u3002";
|
|
2968
|
+
}
|
|
2969
|
+
if (!developer && INTERNAL_CHAT_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
2970
|
+
return GENERIC_CHAT_ERROR;
|
|
2971
|
+
}
|
|
2972
|
+
return normalized || GENERIC_CHAT_ERROR;
|
|
2973
|
+
}
|
|
2711
2974
|
function normalizeMessageContent(content) {
|
|
2712
2975
|
if (typeof content === "string") return content;
|
|
2713
2976
|
if (Array.isArray(content)) return content;
|
|
@@ -2903,10 +3166,10 @@ function inferLoopStatusFromMessages(messages) {
|
|
|
2903
3166
|
}
|
|
2904
3167
|
function inferLoopStatusFromTurns(turns, messages) {
|
|
2905
3168
|
const latestAgentNotification = [...turns].reverse().flatMap((turn) => turn.blocks).find((block) => {
|
|
2906
|
-
if (block.type !== "system_notification" || !
|
|
3169
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) return false;
|
|
2907
3170
|
return block.content.notification_type === "agent:start" || block.content.notification_type === "agent:end";
|
|
2908
3171
|
});
|
|
2909
|
-
if (latestAgentNotification?.type === "system_notification" &&
|
|
3172
|
+
if (latestAgentNotification?.type === "system_notification" && isRecord5(latestAgentNotification.content)) {
|
|
2910
3173
|
const notificationType = latestAgentNotification.content.notification_type;
|
|
2911
3174
|
const status = latestAgentNotification.content.status;
|
|
2912
3175
|
if (notificationType === "agent:start" || status === "running") return "running";
|
|
@@ -2915,17 +3178,47 @@ function inferLoopStatusFromTurns(turns, messages) {
|
|
|
2915
3178
|
}
|
|
2916
3179
|
return inferLoopStatusFromMessages(messages);
|
|
2917
3180
|
}
|
|
2918
|
-
function
|
|
3181
|
+
function isRecord5(value) {
|
|
2919
3182
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2920
3183
|
}
|
|
3184
|
+
function toSelectionMap(value) {
|
|
3185
|
+
if (!isRecord5(value)) return {};
|
|
3186
|
+
const entries = Object.entries(value).map(([questionKey, optionIndexes]) => {
|
|
3187
|
+
if (!Array.isArray(optionIndexes)) return null;
|
|
3188
|
+
const parsedIndexes = optionIndexes.map((item) => typeof item === "number" ? item : Number(item)).filter((item) => Number.isInteger(item));
|
|
3189
|
+
return [Number(questionKey), parsedIndexes];
|
|
3190
|
+
}).filter((entry) => entry !== null);
|
|
3191
|
+
return Object.fromEntries(entries);
|
|
3192
|
+
}
|
|
3193
|
+
function toCustomMap(value) {
|
|
3194
|
+
if (!isRecord5(value)) return {};
|
|
3195
|
+
const entries = Object.entries(value).filter(([, text]) => typeof text === "string").map(([questionKey, text]) => [Number(questionKey), text]);
|
|
3196
|
+
return Object.fromEntries(entries);
|
|
3197
|
+
}
|
|
3198
|
+
function extractAskAnswers(turns) {
|
|
3199
|
+
const answers = {};
|
|
3200
|
+
for (const turn of turns) {
|
|
3201
|
+
for (const block of turn.blocks) {
|
|
3202
|
+
if (block.type !== "ask_user_answer" || typeof block.tool_call_id !== "string") continue;
|
|
3203
|
+
if (!isRecord5(block.content)) continue;
|
|
3204
|
+
const note = typeof block.content.note === "string" ? block.content.note.trim() : "";
|
|
3205
|
+
answers[block.tool_call_id] = {
|
|
3206
|
+
selections: toSelectionMap(block.content.selections),
|
|
3207
|
+
custom: toCustomMap(block.content.custom),
|
|
3208
|
+
...note ? { note } : {}
|
|
3209
|
+
};
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
return answers;
|
|
3213
|
+
}
|
|
2921
3214
|
function parentForkToolCallIdFromTurn(turn) {
|
|
2922
3215
|
if (typeof turn.parent_fork_tool_call_id === "string" && turn.parent_fork_tool_call_id.length > 0) {
|
|
2923
3216
|
return turn.parent_fork_tool_call_id;
|
|
2924
3217
|
}
|
|
2925
3218
|
for (const block of turn.blocks) {
|
|
2926
|
-
if (block.type !== "system_notification" || !
|
|
3219
|
+
if (block.type !== "system_notification" || !isRecord5(block.content)) continue;
|
|
2927
3220
|
const metadata = block.content.metadata;
|
|
2928
|
-
if (!
|
|
3221
|
+
if (!isRecord5(metadata)) continue;
|
|
2929
3222
|
const parentId = metadata.parent_fork_tool_call_id;
|
|
2930
3223
|
if (typeof parentId === "string" && parentId.length > 0) return parentId;
|
|
2931
3224
|
}
|
|
@@ -2942,16 +3235,16 @@ function buildMessageContent2(turn) {
|
|
|
2942
3235
|
}
|
|
2943
3236
|
function workspaceNotificationContent(turn) {
|
|
2944
3237
|
const block = turn.blocks.find(
|
|
2945
|
-
(candidate) => candidate.type === "system_notification" &&
|
|
3238
|
+
(candidate) => candidate.type === "system_notification" && isRecord5(candidate.content) && candidate.content.notification_type === "workspace_change"
|
|
2946
3239
|
);
|
|
2947
|
-
if (!block || !
|
|
3240
|
+
if (!block || !isRecord5(block.content)) return "";
|
|
2948
3241
|
const title = typeof block.content.title === "string" ? block.content.title.trim() : "";
|
|
2949
3242
|
const detail = typeof block.content.detail === "string" ? block.content.detail.trim() : "";
|
|
2950
3243
|
return [title ? `**${title}**` : "", detail].filter(Boolean).join("\n\n");
|
|
2951
3244
|
}
|
|
2952
3245
|
function askUserAnswerContent(turn) {
|
|
2953
3246
|
const answerBlock = turn.blocks.find((block) => block.type === "ask_user_answer");
|
|
2954
|
-
if (!answerBlock || !
|
|
3247
|
+
if (!answerBlock || !isRecord5(answerBlock.content)) return null;
|
|
2955
3248
|
const answer = answerBlock.content.answer;
|
|
2956
3249
|
return typeof answer === "string" && answer.trim().length > 0 ? answer : null;
|
|
2957
3250
|
}
|
|
@@ -2971,6 +3264,19 @@ function extractModeFromBlocks(blocks) {
|
|
|
2971
3264
|
return null;
|
|
2972
3265
|
}
|
|
2973
3266
|
function projectionToMessage(turn) {
|
|
3267
|
+
if (turn.kind === "context") {
|
|
3268
|
+
const context = contextProjectionData(turn);
|
|
3269
|
+
if (!context) return null;
|
|
3270
|
+
return {
|
|
3271
|
+
role: "assistant",
|
|
3272
|
+
content: "",
|
|
3273
|
+
kind: "context",
|
|
3274
|
+
context,
|
|
3275
|
+
loop_name: turn.loop_id,
|
|
3276
|
+
entry_id: turn.turn_id,
|
|
3277
|
+
status: turn.status
|
|
3278
|
+
};
|
|
3279
|
+
}
|
|
2974
3280
|
if (turn.kind === "compaction" && turn.compaction_id) {
|
|
2975
3281
|
return {
|
|
2976
3282
|
role: "assistant",
|
|
@@ -3140,6 +3446,25 @@ function orderTurns(turns) {
|
|
|
3140
3446
|
}
|
|
3141
3447
|
return turns;
|
|
3142
3448
|
}
|
|
3449
|
+
function reconcileOptimisticUserTurns(currentTurns, incomingTurns) {
|
|
3450
|
+
const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]));
|
|
3451
|
+
const optimisticUserTurn = currentTurns.find(
|
|
3452
|
+
(turn) => turn.role === "user" && (turn.kind ?? "message") === "message" && turn.turn_id.startsWith("local-user-")
|
|
3453
|
+
);
|
|
3454
|
+
let optimisticUserMatched = false;
|
|
3455
|
+
return incomingTurns.map((turn) => {
|
|
3456
|
+
const current = currentById.get(turn.turn_id);
|
|
3457
|
+
if (current) {
|
|
3458
|
+
const currentRenderId = current.client_render_id;
|
|
3459
|
+
return turn.client_render_id || !currentRenderId ? turn : { ...turn, client_render_id: currentRenderId };
|
|
3460
|
+
}
|
|
3461
|
+
if (!optimisticUserMatched && optimisticUserTurn && turn.role === "user" && (turn.kind ?? "message") === "message" && !turn.turn_id.startsWith("local-user-")) {
|
|
3462
|
+
optimisticUserMatched = true;
|
|
3463
|
+
return { ...turn, client_render_id: optimisticUserTurn.turn_id };
|
|
3464
|
+
}
|
|
3465
|
+
return turn;
|
|
3466
|
+
});
|
|
3467
|
+
}
|
|
3143
3468
|
function areAgentLoopsEqual(left, right) {
|
|
3144
3469
|
if (!left) return Object.keys(right).length === 0;
|
|
3145
3470
|
const leftEntries = Object.entries(left);
|
|
@@ -3151,7 +3476,7 @@ function areAgentLoopsEqual(left, right) {
|
|
|
3151
3476
|
});
|
|
3152
3477
|
}
|
|
3153
3478
|
function withTurns(state, turns) {
|
|
3154
|
-
const orderedTurns = orderTurns(turns);
|
|
3479
|
+
const orderedTurns = orderTurns(reconcileOptimisticUserTurns(state.turns, turns));
|
|
3155
3480
|
const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
|
|
3156
3481
|
const isWaitingForInput = orderedTurns.some(
|
|
3157
3482
|
(turn) => turn.tool_calls.some((toolCall) => toolCall.status === "awaiting_answer")
|
|
@@ -3161,14 +3486,31 @@ function withTurns(state, turns) {
|
|
|
3161
3486
|
const preservedErrors = lastTurnId ? state.messages.filter(
|
|
3162
3487
|
(m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
|
|
3163
3488
|
) : [];
|
|
3164
|
-
const
|
|
3489
|
+
const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]));
|
|
3490
|
+
const messagesWithRenderIds = messages.map((message) => {
|
|
3491
|
+
if (!message.entry_id) return message;
|
|
3492
|
+
const renderId = turnById.get(message.entry_id)?.client_render_id;
|
|
3493
|
+
return renderId ? { ...message, render_id: renderId } : message;
|
|
3494
|
+
});
|
|
3495
|
+
const mergedMessages = preservedErrors.length > 0 ? [...messagesWithRenderIds, ...preservedErrors] : messagesWithRenderIds;
|
|
3165
3496
|
const latestMode = [...orderedTurns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
|
|
3497
|
+
const askAnswersFromHistory = extractAskAnswers(orderedTurns);
|
|
3498
|
+
const presentToolCallIds = new Set(
|
|
3499
|
+
orderedTurns.flatMap((turn) => turn.tool_calls.map((toolCall) => toolCall.id))
|
|
3500
|
+
);
|
|
3501
|
+
const askAnswers = { ...askAnswersFromHistory };
|
|
3502
|
+
for (const [toolCallId, answer] of Object.entries(state.askAnswers)) {
|
|
3503
|
+
if (!(toolCallId in askAnswers) && presentToolCallIds.has(toolCallId)) {
|
|
3504
|
+
askAnswers[toolCallId] = answer;
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3166
3507
|
return {
|
|
3167
3508
|
...state,
|
|
3168
3509
|
turns: orderedTurns,
|
|
3169
3510
|
messages: mergedMessages,
|
|
3170
3511
|
agentLoops: stableAgentLoops,
|
|
3171
3512
|
activeCompaction,
|
|
3513
|
+
askAnswers,
|
|
3172
3514
|
mode: latestMode ?? state.mode,
|
|
3173
3515
|
// 历史恢复时 chat:end(paused) 可能已不在 socket replay 缓存中;
|
|
3174
3516
|
// awaiting_answer 是投影里的持久权威状态,必须据此恢复问答交互。
|
|
@@ -3196,14 +3538,17 @@ function addUserMessage(state, content) {
|
|
|
3196
3538
|
}
|
|
3197
3539
|
function upsertTurn(state, turn) {
|
|
3198
3540
|
let existing = [...state.turns];
|
|
3199
|
-
|
|
3200
|
-
|
|
3541
|
+
const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn]);
|
|
3542
|
+
if (nextTurn.client_render_id && turn.role === "user") {
|
|
3543
|
+
existing = existing.filter(
|
|
3544
|
+
(item) => !(item.role === "user" && item.turn_id.startsWith("local-user-"))
|
|
3545
|
+
);
|
|
3201
3546
|
}
|
|
3202
|
-
const index = existing.findIndex((item) => item.turn_id ===
|
|
3547
|
+
const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id);
|
|
3203
3548
|
if (index >= 0) {
|
|
3204
|
-
existing[index] =
|
|
3549
|
+
existing[index] = nextTurn;
|
|
3205
3550
|
} else {
|
|
3206
|
-
existing.push(
|
|
3551
|
+
existing.push(nextTurn);
|
|
3207
3552
|
}
|
|
3208
3553
|
return withTurns(state, existing);
|
|
3209
3554
|
}
|
|
@@ -3255,18 +3600,18 @@ function markStreamingTurns(state, turnStatus, toolCallStatus) {
|
|
|
3255
3600
|
// src/session/agent-session.ts
|
|
3256
3601
|
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
3602
|
var OOM_KEYWORDS_RE = /(?:\b(?:exit_code|ExitedWith|exited with)|退出码)\D*(?<!\d)137(?!\d)/i;
|
|
3258
|
-
function
|
|
3603
|
+
function isRecord6(value) {
|
|
3259
3604
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3260
3605
|
}
|
|
3261
3606
|
function isOomText(value) {
|
|
3262
3607
|
return typeof value === "string" && OOM_KEYWORDS_RE.test(value);
|
|
3263
3608
|
}
|
|
3264
3609
|
function parseJsonRecord(value) {
|
|
3265
|
-
if (
|
|
3610
|
+
if (isRecord6(value)) return value;
|
|
3266
3611
|
if (typeof value !== "string") return null;
|
|
3267
3612
|
try {
|
|
3268
3613
|
const parsed = JSON.parse(value);
|
|
3269
|
-
return
|
|
3614
|
+
return isRecord6(parsed) ? parsed : null;
|
|
3270
3615
|
} catch {
|
|
3271
3616
|
return null;
|
|
3272
3617
|
}
|
|
@@ -3313,7 +3658,7 @@ function hasChatRunEvent2(events) {
|
|
|
3313
3658
|
);
|
|
3314
3659
|
}
|
|
3315
3660
|
function isUiMetaLike(value) {
|
|
3316
|
-
return
|
|
3661
|
+
return isRecord6(value) && ("resourceHTML" in value || "resourceUri" in value || "resourceURI" in value);
|
|
3317
3662
|
}
|
|
3318
3663
|
var AgentSession = class _AgentSession {
|
|
3319
3664
|
sessionId;
|
|
@@ -3335,6 +3680,7 @@ var AgentSession = class _AgentSession {
|
|
|
3335
3680
|
replayQueue = Promise.resolve();
|
|
3336
3681
|
pendingReplayMessage = null;
|
|
3337
3682
|
pendingReplayMode;
|
|
3683
|
+
pendingReplayKbIds;
|
|
3338
3684
|
recentChatEndAt = 0;
|
|
3339
3685
|
disposed = false;
|
|
3340
3686
|
getAppContext = null;
|
|
@@ -3359,7 +3705,6 @@ var AgentSession = class _AgentSession {
|
|
|
3359
3705
|
const session = new _AgentSession(
|
|
3360
3706
|
sessionId,
|
|
3361
3707
|
{
|
|
3362
|
-
streamTokens: false,
|
|
3363
3708
|
emitEvent: readonlyError,
|
|
3364
3709
|
emitWithAck: async () => readonlyError(),
|
|
3365
3710
|
ensureConnected: readonlyError,
|
|
@@ -3464,7 +3809,7 @@ var AgentSession = class _AgentSession {
|
|
|
3464
3809
|
if (this.getAppContext) {
|
|
3465
3810
|
try {
|
|
3466
3811
|
const rawContext = await this.getAppContext();
|
|
3467
|
-
if (!
|
|
3812
|
+
if (!isRecord6(rawContext)) {
|
|
3468
3813
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3469
3814
|
}
|
|
3470
3815
|
const serialized = JSON.stringify(rawContext);
|
|
@@ -3472,7 +3817,7 @@ var AgentSession = class _AgentSession {
|
|
|
3472
3817
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE\u53EF\u5E8F\u5217\u5316\u7684 JSON \u5BF9\u8C61");
|
|
3473
3818
|
}
|
|
3474
3819
|
const normalized = JSON.parse(serialized);
|
|
3475
|
-
if (!
|
|
3820
|
+
if (!isRecord6(normalized)) {
|
|
3476
3821
|
throw new Error("getContext \u5FC5\u987B\u8FD4\u56DE JSON \u5BF9\u8C61");
|
|
3477
3822
|
}
|
|
3478
3823
|
appContext = normalized;
|
|
@@ -3486,13 +3831,11 @@ var AgentSession = class _AgentSession {
|
|
|
3486
3831
|
let optimisticTurnId = null;
|
|
3487
3832
|
let optimisticAskAnswer;
|
|
3488
3833
|
let previousAskAnswer;
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
});
|
|
3495
|
-
}
|
|
3834
|
+
this.update((state) => {
|
|
3835
|
+
const next = addUserMessage(state, content);
|
|
3836
|
+
optimisticTurnId = next.turns.at(-1)?.turn_id ?? null;
|
|
3837
|
+
return next;
|
|
3838
|
+
});
|
|
3496
3839
|
this.update((s) => ({ ...s, isStreaming: true }));
|
|
3497
3840
|
if (askUserAnswer && typeof askUserAnswer.tool_call_id === "string") {
|
|
3498
3841
|
const { tool_call_id, ...rest } = askUserAnswer;
|
|
@@ -3506,6 +3849,7 @@ var AgentSession = class _AgentSession {
|
|
|
3506
3849
|
if (!options.replayDecision) {
|
|
3507
3850
|
this.pendingReplayMessage = content;
|
|
3508
3851
|
this.pendingReplayMode = options.mode;
|
|
3852
|
+
this.pendingReplayKbIds = options.kbIds;
|
|
3509
3853
|
}
|
|
3510
3854
|
const payload = {
|
|
3511
3855
|
session_id: this.sessionId,
|
|
@@ -3516,7 +3860,8 @@ var AgentSession = class _AgentSession {
|
|
|
3516
3860
|
thinking_override: options.thinkingOverride,
|
|
3517
3861
|
whatif: options.whatif,
|
|
3518
3862
|
replay_decision: options.replayDecision,
|
|
3519
|
-
app_context: appContext
|
|
3863
|
+
app_context: appContext,
|
|
3864
|
+
kb_ids: options.kbIds && options.kbIds.length > 0 ? options.kbIds : void 0
|
|
3520
3865
|
};
|
|
3521
3866
|
try {
|
|
3522
3867
|
await this.ensureJoined();
|
|
@@ -3552,6 +3897,7 @@ var AgentSession = class _AgentSession {
|
|
|
3552
3897
|
rollbackOptimisticSend(optimisticTurnId, askUserAnswer, optimisticAskAnswer, previousAskAnswer, message) {
|
|
3553
3898
|
this.pendingReplayMessage = null;
|
|
3554
3899
|
this.pendingReplayMode = void 0;
|
|
3900
|
+
this.pendingReplayKbIds = void 0;
|
|
3555
3901
|
this.update((current) => {
|
|
3556
3902
|
let next = optimisticTurnId ? withTurns(
|
|
3557
3903
|
current,
|
|
@@ -3733,7 +4079,7 @@ var AgentSession = class _AgentSession {
|
|
|
3733
4079
|
_handleTurnEvents(events) {
|
|
3734
4080
|
if (!events.length) return;
|
|
3735
4081
|
const terminalChatEndStatus = extractTerminalChatEndStatus(events);
|
|
3736
|
-
if (!terminalChatEndStatus && hasChatRunEvent2(events)) {
|
|
4082
|
+
if (!terminalChatEndStatus && hasChatRunEvent2(events) && this.state.status !== "waiting_for_input") {
|
|
3737
4083
|
this.markRunningIfIdle();
|
|
3738
4084
|
}
|
|
3739
4085
|
if (this.state.turns.length) {
|
|
@@ -3805,8 +4151,10 @@ var AgentSession = class _AgentSession {
|
|
|
3805
4151
|
_handleReplayMismatch(data) {
|
|
3806
4152
|
const message = this.pendingReplayMessage ?? data.actual_message ?? "";
|
|
3807
4153
|
const mode = this.pendingReplayMode;
|
|
4154
|
+
const kbIds = this.pendingReplayKbIds;
|
|
3808
4155
|
this.pendingReplayMessage = null;
|
|
3809
4156
|
this.pendingReplayMode = void 0;
|
|
4157
|
+
this.pendingReplayKbIds = void 0;
|
|
3810
4158
|
const respond = (decision) => {
|
|
3811
4159
|
void this.runtime.emitWithAck(
|
|
3812
4160
|
"chat:send",
|
|
@@ -3814,7 +4162,8 @@ var AgentSession = class _AgentSession {
|
|
|
3814
4162
|
session_id: this.sessionId,
|
|
3815
4163
|
message,
|
|
3816
4164
|
mode,
|
|
3817
|
-
replay_decision: decision
|
|
4165
|
+
replay_decision: decision,
|
|
4166
|
+
kb_ids: kbIds && kbIds.length > 0 ? kbIds : void 0
|
|
3818
4167
|
},
|
|
3819
4168
|
3e4
|
|
3820
4169
|
).then((response) => {
|
|
@@ -3855,9 +4204,9 @@ var AgentSession = class _AgentSession {
|
|
|
3855
4204
|
detail,
|
|
3856
4205
|
status,
|
|
3857
4206
|
loopId,
|
|
3858
|
-
metadata:
|
|
4207
|
+
metadata: isRecord6(notification.metadata) ? notification.metadata : void 0
|
|
3859
4208
|
});
|
|
3860
|
-
if (notificationType === "bg:started" &&
|
|
4209
|
+
if (notificationType === "bg:started" && isRecord6(notification.metadata)) {
|
|
3861
4210
|
const taskId = typeof notification.metadata.task_id === "string" ? notification.metadata.task_id : "";
|
|
3862
4211
|
if (taskId) {
|
|
3863
4212
|
this.emitter.emit("backgroundTask", {
|
|
@@ -3987,7 +4336,7 @@ var AgentSession = class _AgentSession {
|
|
|
3987
4336
|
title: ui.title ?? "\u5DE5\u5177\u9884\u89C8"
|
|
3988
4337
|
});
|
|
3989
4338
|
}
|
|
3990
|
-
if (block.type === "system_notification" &&
|
|
4339
|
+
if (block.type === "system_notification" && isRecord6(block.content)) {
|
|
3991
4340
|
this._handleSystemNotification(turn.loop_id, block.content);
|
|
3992
4341
|
}
|
|
3993
4342
|
}
|
|
@@ -4093,8 +4442,7 @@ var AgentSession = class _AgentSession {
|
|
|
4093
4442
|
{
|
|
4094
4443
|
session_id: this.sessionId,
|
|
4095
4444
|
event_format: "raw",
|
|
4096
|
-
resume: true
|
|
4097
|
-
stream_tokens: this.runtime.streamTokens
|
|
4445
|
+
resume: true
|
|
4098
4446
|
},
|
|
4099
4447
|
5e3
|
|
4100
4448
|
).then((response) => {
|
|
@@ -4231,7 +4579,6 @@ var SessionHub = class {
|
|
|
4231
4579
|
}
|
|
4232
4580
|
runtimeFor() {
|
|
4233
4581
|
return {
|
|
4234
|
-
streamTokens: this.client.options?.streamTokens !== false,
|
|
4235
4582
|
emitEvent: (event, data) => {
|
|
4236
4583
|
;
|
|
4237
4584
|
this.client.socket().emit(event, data);
|
|
@@ -4471,7 +4818,7 @@ function resolveAuthToken(options) {
|
|
|
4471
4818
|
|
|
4472
4819
|
// src/version.ts
|
|
4473
4820
|
var SDK_NAME = "agent-client";
|
|
4474
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
4821
|
+
var SDK_VERSION = true ? "2610.0.0-beta.30" : "1.1.1";
|
|
4475
4822
|
|
|
4476
4823
|
// src/socket.ts
|
|
4477
4824
|
function withSdkIdentity(auth) {
|
|
@@ -4499,6 +4846,7 @@ var BladeClient = class {
|
|
|
4499
4846
|
options;
|
|
4500
4847
|
auth;
|
|
4501
4848
|
headless;
|
|
4849
|
+
computers;
|
|
4502
4850
|
models;
|
|
4503
4851
|
sessions;
|
|
4504
4852
|
/** 实时会话中枢:client.sessions.connect() 内部使用,一般不直接访问。 */
|
|
@@ -4510,6 +4858,7 @@ var BladeClient = class {
|
|
|
4510
4858
|
};
|
|
4511
4859
|
this.auth = new AuthResource(this);
|
|
4512
4860
|
this.headless = new HeadlessResource(this);
|
|
4861
|
+
this.computers = new ComputersResource(this);
|
|
4513
4862
|
this.models = new ModelsResource(this);
|
|
4514
4863
|
this.sessions = new SessionsResource(this);
|
|
4515
4864
|
this.hub = new SessionHub(this);
|
|
@@ -4864,6 +5213,89 @@ function parseXhrHeaders(rawHeaders) {
|
|
|
4864
5213
|
return headers;
|
|
4865
5214
|
}
|
|
4866
5215
|
|
|
5216
|
+
// src/platform-endpoints.ts
|
|
5217
|
+
var PLATFORM_SERVICE_NAMES = [
|
|
5218
|
+
"os",
|
|
5219
|
+
"hub",
|
|
5220
|
+
"agent",
|
|
5221
|
+
"oauth",
|
|
5222
|
+
"llmGateway",
|
|
5223
|
+
"gitea",
|
|
5224
|
+
"tile"
|
|
5225
|
+
];
|
|
5226
|
+
var EMPTY_PLATFORM_ENDPOINTS = Object.freeze({
|
|
5227
|
+
services: Object.freeze({})
|
|
5228
|
+
});
|
|
5229
|
+
function defaultDocumentBaseUrl() {
|
|
5230
|
+
if (typeof document === "undefined") return void 0;
|
|
5231
|
+
if (document.querySelector("base[href]")) return document.baseURI;
|
|
5232
|
+
if (typeof location !== "undefined" && location.origin) return `${location.origin}/`;
|
|
5233
|
+
return document.baseURI;
|
|
5234
|
+
}
|
|
5235
|
+
function isRecord7(value) {
|
|
5236
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5237
|
+
}
|
|
5238
|
+
function normalizeServiceUrl(value) {
|
|
5239
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
5240
|
+
if (value.includes("?") || value.includes("#")) return null;
|
|
5241
|
+
try {
|
|
5242
|
+
const url = new URL(value.trim());
|
|
5243
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
5244
|
+
if (url.username || url.password || url.search || url.hash) return null;
|
|
5245
|
+
return url.toString().replace(/\/$/, "");
|
|
5246
|
+
} catch {
|
|
5247
|
+
return null;
|
|
5248
|
+
}
|
|
5249
|
+
}
|
|
5250
|
+
function parsePlatformEndpoints(value) {
|
|
5251
|
+
if (!isRecord7(value) || !isRecord7(value.services)) return null;
|
|
5252
|
+
const services = {};
|
|
5253
|
+
for (const name of PLATFORM_SERVICE_NAMES) {
|
|
5254
|
+
if (!(name in value.services)) continue;
|
|
5255
|
+
const url = normalizeServiceUrl(value.services[name]);
|
|
5256
|
+
if (!url) return null;
|
|
5257
|
+
if (name === "agent" && new URL(url).pathname !== "/") return null;
|
|
5258
|
+
services[name] = url;
|
|
5259
|
+
}
|
|
5260
|
+
return { services };
|
|
5261
|
+
}
|
|
5262
|
+
async function loadPlatformEndpoints(options = {}) {
|
|
5263
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
5264
|
+
const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl();
|
|
5265
|
+
if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS;
|
|
5266
|
+
const controller = new AbortController();
|
|
5267
|
+
const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3e3);
|
|
5268
|
+
try {
|
|
5269
|
+
const response = await fetchImpl(new URL("config.json", baseUrl), {
|
|
5270
|
+
cache: "no-store",
|
|
5271
|
+
credentials: "same-origin",
|
|
5272
|
+
headers: { Accept: "application/json" },
|
|
5273
|
+
signal: controller.signal
|
|
5274
|
+
});
|
|
5275
|
+
if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS;
|
|
5276
|
+
return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS;
|
|
5277
|
+
} catch {
|
|
5278
|
+
return EMPTY_PLATFORM_ENDPOINTS;
|
|
5279
|
+
} finally {
|
|
5280
|
+
globalThis.clearTimeout(timeout);
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
function resolveServiceUrl(endpoints, name, path = "") {
|
|
5284
|
+
const baseUrl = endpoints.services[name];
|
|
5285
|
+
if (!baseUrl) return null;
|
|
5286
|
+
if (!path) return baseUrl;
|
|
5287
|
+
const pathReference = path.trimStart();
|
|
5288
|
+
if (path.includes("\\") || pathReference.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(pathReference)) {
|
|
5289
|
+
return null;
|
|
5290
|
+
}
|
|
5291
|
+
const base = new URL(`${baseUrl}/`);
|
|
5292
|
+
const target = new URL(path.replace(/^\/+/, ""), base);
|
|
5293
|
+
if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {
|
|
5294
|
+
return null;
|
|
5295
|
+
}
|
|
5296
|
+
return target.toString();
|
|
5297
|
+
}
|
|
5298
|
+
|
|
4867
5299
|
// src/commands/protocol.ts
|
|
4868
5300
|
function isCommandEnvelope(value) {
|
|
4869
5301
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -4967,7 +5399,9 @@ export {
|
|
|
4967
5399
|
BladeApiError,
|
|
4968
5400
|
BladeClient,
|
|
4969
5401
|
ClientProjectionBuilder,
|
|
5402
|
+
ComputersResource,
|
|
4970
5403
|
DEFAULT_REPLAY_SPEED,
|
|
5404
|
+
EMPTY_PLATFORM_ENDPOINTS,
|
|
4971
5405
|
LayoutType,
|
|
4972
5406
|
ModelsResource,
|
|
4973
5407
|
SDK_NAME,
|
|
@@ -4980,11 +5414,16 @@ export {
|
|
|
4980
5414
|
TaskStatus,
|
|
4981
5415
|
acceptedPostChatFollowupCompletesLatestRun,
|
|
4982
5416
|
buildMessageContent,
|
|
5417
|
+
canToggleComputer,
|
|
5418
|
+
chatErrorForDisplay,
|
|
5419
|
+
computerState,
|
|
4983
5420
|
connectEmbedded,
|
|
4984
5421
|
contentPreview,
|
|
5422
|
+
contextProjectionData,
|
|
4985
5423
|
createInitialSessionState,
|
|
4986
5424
|
createSocket,
|
|
4987
5425
|
extractTextAttachments,
|
|
5426
|
+
getContextDisplayState,
|
|
4988
5427
|
getFileParts,
|
|
4989
5428
|
getImageParts,
|
|
4990
5429
|
getTextContent,
|
|
@@ -4993,7 +5432,11 @@ export {
|
|
|
4993
5432
|
isHiddenInternalMessage,
|
|
4994
5433
|
isInboundEnvelope,
|
|
4995
5434
|
latestPostChatFollowup,
|
|
5435
|
+
loadPlatformEndpoints,
|
|
4996
5436
|
normalizeMessageContent,
|
|
5437
|
+
reconcileOptimisticUserTurns,
|
|
5438
|
+
resolveServiceUrl,
|
|
5439
|
+
sortComputers,
|
|
4997
5440
|
toReplaySnapshot,
|
|
4998
5441
|
transformSlashCommand
|
|
4999
5442
|
};
|