@blade-hq/agent-client 2610.0.0-beta.54 → 2610.0.0-beta.55
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 -1
- package/dist/blade-client.d.ts +5 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +167 -27
- package/dist/index.js.map +1 -1
- package/dist/resources/{chat-projects.d.ts → chat-groups.d.ts} +7 -7
- package/dist/resources/computers.d.ts +30 -0
- package/dist/resources/plugins.d.ts +43 -0
- package/dist/resources/sessions.d.ts +13 -3
- package/dist/schemas/projection.d.ts +17 -1
- package/dist/schemas/session.d.ts +2 -2
- package/dist/shared/projection/builder.d.ts +3 -0
- package/dist/shared/projection/helpers.d.ts +1 -1
- package/dist/shared/projection/state.d.ts +4 -0
- package/package.json +1 -1
- package/public-api.md +71 -28
package/README.md
CHANGED
|
@@ -174,6 +174,32 @@ await client.sessions.getSessionTurnsPage(id, { before: page.nextBefore! })
|
|
|
174
174
|
会话插件可通过 `client.sessions.listSessionPlugins(id)` 查询,并用
|
|
175
175
|
`client.sessions.setSessionPluginActivation(id, name, active)` 切换当前会话。列表项为 `SessionPlugin`;修改结果为 `SessionPluginActivation`,只返回选择和准备状态,安装事实需从列表获取。
|
|
176
176
|
|
|
177
|
+
账号级目录是 `client.plugins.catalog()`(`PluginsResource` 是 `client.plugins`
|
|
178
|
+
的类型)。它**不依赖任何会话**,返回 `PluginCatalogEntry[]`:`name`、`display_name`、
|
|
179
|
+
`icon`、`installed`。没有会话也要展示插件名称与图标的界面(例如首页的输入框连接器)
|
|
180
|
+
用它,而不是先建一个会话。
|
|
181
|
+
|
|
182
|
+
`icon` 是不透明的缓存 token(当前是包内容摘要),**不是路径**:把它交给
|
|
183
|
+
`client.plugins.fetchIcon(name)` 取字节再转 object URL,不要拿它拼 URL,也不要把
|
|
184
|
+
`<img>` 指向接口路径(token 用户会拿到 401/403)。
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const { plugins } = await client.plugins.catalog()
|
|
188
|
+
// plugins: PluginCatalogEntry[]
|
|
189
|
+
// name 技术 ID:路径、授权、缓存与调用一律用它
|
|
190
|
+
// display_name 包声明的业务名;null 时界面回退到 name
|
|
191
|
+
// icon 包内图标的 opaque token;null 表示没有可用图标
|
|
192
|
+
// installed 当前用户是否安装了它
|
|
193
|
+
|
|
194
|
+
const blob = await client.plugins.fetchIcon(plugins[0].name)
|
|
195
|
+
const url = URL.createObjectURL(blob)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
账号电脑目录是 `client.computers.listAccount()`,返回 `AccountComputerList`。它只回答
|
|
199
|
+
账号事实(登记过哪些电脑、此刻在不在线,`AccountComputer`),**不含**"本次会话能不能
|
|
200
|
+
用它"——那是会话接口 (`client.computers.list`) 的回答。两者混着说,用户就会把在线当成
|
|
201
|
+
已授权。
|
|
202
|
+
|
|
177
203
|
插件可以在包内 `cn.com.bladeai.agent/config.schema.json` 用标准 JSON Schema
|
|
178
204
|
(Draft 2020-12)声明账号、token 或任意业务配置。声明了配置的插件用
|
|
179
205
|
`client.sessions.getSessionPluginConfig(id, name)` 读取声明与当前值,用
|
|
@@ -706,7 +732,9 @@ HTML 一律判无效);`isInternalStatusToolUiCard` 识别内部「阶段进
|
|
|
706
732
|
- **SDK 身份**:`SDK_NAME`、`SDK_VERSION`
|
|
707
733
|
- **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
|
|
708
734
|
- **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
|
|
709
|
-
-
|
|
735
|
+
- **聊天分组资源(REST)**:`ChatGroupsResource`、`ChatGroup`(含 `delete` 永久删除);`client.chatGroups`。旧名 `ChatProjectsResource`、`ChatProject`、`client.chatProjects` 与 `chat_project_id` 字段已随分组改名一并移除,接入方请改用 `chatGroups` 与 `chat_group_id`
|
|
736
|
+
- **插件目录(REST,无会话)**:`PluginsResource`、`PluginCatalogEntry`(`client.plugins`)。首页这类还没有会话的界面用它读名称、业务名与图标 token
|
|
737
|
+
- **账号电脑目录**:`AccountComputer`、`AccountComputerList`(`client.computers.listAccount()`,只读账号事实,不含会话授权)
|
|
710
738
|
- **全站访问统计(REST)**:`SiteVisitsResource`、`SiteVisitsSummary`(`client.siteVisits.record()` 上报一次页面访问、`client.siteVisits.summary()` 只读快照)。这两个操作走独立匿名传输:不带 bearer、不触发 401 登录刷新,只依赖匿名访客 Cookie,供内置 Web 同源使用。
|
|
711
739
|
- **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`GlobalSearchResult`、`GlobalSearchResultItem`、`GlobalSearchConversationResult`、`GlobalSearchFileResult`、`SessionHistory`、`SessionContextStats`、`ResultFeedback`、`ResultFeedbackReason`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`
|
|
712
740
|
- **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
|
package/dist/blade-client.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { HeadlessResource } from "./resources/headless";
|
|
|
5
5
|
import { ComputersResource } from "./resources/computers";
|
|
6
6
|
import { ModelsResource } from "./resources/models";
|
|
7
7
|
import { SessionsResource } from "./resources/sessions";
|
|
8
|
-
import {
|
|
8
|
+
import { PluginsResource } from "./resources/plugins";
|
|
9
|
+
import { ChatGroupsResource } from "./resources/chat-groups";
|
|
9
10
|
import { SiteVisitsResource } from "./resources/site-visits";
|
|
10
11
|
import { SessionHub } from "./session/hub";
|
|
11
12
|
import { type TypedSocket } from "./socket";
|
|
@@ -39,7 +40,9 @@ export declare class BladeClient {
|
|
|
39
40
|
readonly computers: ComputersResource;
|
|
40
41
|
readonly models: ModelsResource;
|
|
41
42
|
readonly sessions: SessionsResource;
|
|
42
|
-
|
|
43
|
+
/** 按用户读取的插件目录与图标;没有会话时也能用。 */
|
|
44
|
+
readonly plugins: PluginsResource;
|
|
45
|
+
readonly chatGroups: ChatGroupsResource;
|
|
43
46
|
/**
|
|
44
47
|
* 全站访问统计:匿名读写,不带 bearer 也不触发登录刷新。
|
|
45
48
|
* 只有内置 Web 的同源页面使用,第三方宿主页面不会被自动统计。
|
package/dist/index.d.ts
CHANGED
|
@@ -28,14 +28,16 @@ export type { AuthResource, ExchangeCodeParams, ExchangeCodeResult, ProvidersRes
|
|
|
28
28
|
export type { HeadlessResource } from "./resources/headless";
|
|
29
29
|
export { ComputersResource } from "./resources/computers";
|
|
30
30
|
export { canToggleComputer, computerDaemonVersion, computerOS, computerPlatformLabel, computerState, sortComputers, } from "./resources/computers";
|
|
31
|
-
export type { ComputerOS, ComputerState, SessionComputer, SessionComputerList, } from "./resources/computers";
|
|
31
|
+
export type { AccountComputer, AccountComputerList, ComputerOS, ComputerState, SessionComputer, SessionComputerList, } from "./resources/computers";
|
|
32
32
|
export { ModelsResource } from "./resources/models";
|
|
33
33
|
export type { ModelCatalog, ModelOption } from "./resources/models";
|
|
34
34
|
export type { SessionsResource } from "./resources/sessions";
|
|
35
35
|
export type { SessionPlugin, SessionPluginActivation } from "./resources/sessions";
|
|
36
36
|
export type { SessionPluginConfigError, SessionPluginConfigSet, SessionPluginConfigState, SessionPluginConfigStateName, SessionPluginConfigSummary, SessionPluginConfigUpdate, } from "./resources/sessions";
|
|
37
|
-
export {
|
|
38
|
-
export type {
|
|
37
|
+
export { ChatGroupsResource } from "./resources/chat-groups";
|
|
38
|
+
export type { ChatGroup } from "./resources/chat-groups";
|
|
39
|
+
export { PluginsResource } from "./resources/plugins";
|
|
40
|
+
export type { PluginCatalogEntry } from "./resources/plugins";
|
|
39
41
|
export type { SiteVisitsResource, SiteVisitsSummary } from "./resources/site-visits";
|
|
40
42
|
export { hasChatRunEvent } from "./shared/projection";
|
|
41
43
|
export type { CreateSessionRequest, AppCliAttachment, AppCliDefinition, FileEntry, ImportSessionOptions, PaginatedSessionsResult, GlobalSearchConversationResult, GlobalSearchFileResult, GlobalSearchResult, GlobalSearchResultItem, ResultFeedback, ResultFeedbackReason, HistoricalCommand, SessionContextStats, SessionHistory, SessionTurnsPage, ShareLinkResult, UploadFileEntry, UploadFilesOptions, } from "./resources/sessions";
|
package/dist/index.js
CHANGED
|
@@ -467,6 +467,21 @@ var ComputersResource = class {
|
|
|
467
467
|
this.client = client;
|
|
468
468
|
}
|
|
469
469
|
client;
|
|
470
|
+
/**
|
|
471
|
+
* 列出当前账号登记过的全部电脑及其在线状态。
|
|
472
|
+
*
|
|
473
|
+
* 首页还没有会话,也要能看到同一份清单——判定各写一份必然分叉,一边的兜底会把
|
|
474
|
+
* 另一边的错误盖住(#1597)。所以账号事实只从这一个接口读。
|
|
475
|
+
*/
|
|
476
|
+
async listAccount() {
|
|
477
|
+
const data = await this.client.json("GET", "/api/daemon/instances");
|
|
478
|
+
return {
|
|
479
|
+
computers: (data.instances ?? []).map((instance) => ({
|
|
480
|
+
...instance,
|
|
481
|
+
online: Boolean(instance.online)
|
|
482
|
+
}))
|
|
483
|
+
};
|
|
484
|
+
}
|
|
470
485
|
/**
|
|
471
486
|
* 列出当前用户的全部电脑,带上"在不在线"和"这次会话能不能用"。
|
|
472
487
|
* 服务端只查库,电脑离线时同样返回,所以拿得到"它离线了"这个结论。
|
|
@@ -542,7 +557,7 @@ var SessionInfo = type({
|
|
|
542
557
|
"workspace_path?": "string | null",
|
|
543
558
|
"ba_version?": "string | null",
|
|
544
559
|
"sandbox_version?": "string | null",
|
|
545
|
-
"
|
|
560
|
+
"chat_group_id?": "string | null",
|
|
546
561
|
"match?": "unknown"
|
|
547
562
|
});
|
|
548
563
|
|
|
@@ -608,7 +623,7 @@ function upsertToolCall(state, toolCallId, toolName, displayName, args) {
|
|
|
608
623
|
});
|
|
609
624
|
}
|
|
610
625
|
}
|
|
611
|
-
function applyToolResult(state, toolCallId, result, status, durationMs, ranInParallel, sourceLoop) {
|
|
626
|
+
function applyToolResult(state, toolCallId, result, status, durationMs, ranInParallel, sourceLoop, startedAt = null) {
|
|
612
627
|
let toolName = "";
|
|
613
628
|
let displayName = "";
|
|
614
629
|
let finalResult = result;
|
|
@@ -621,6 +636,7 @@ function applyToolResult(state, toolCallId, result, status, durationMs, ranInPar
|
|
|
621
636
|
const update = { status, result: finalResult };
|
|
622
637
|
if (durationMs != null) update.duration_ms = durationMs;
|
|
623
638
|
if (ranInParallel != null) update.ran_in_parallel = ranInParallel;
|
|
639
|
+
if (startedAt != null) update.started_at = startedAt;
|
|
624
640
|
state.toolCalls[i] = { ...tc, ...update };
|
|
625
641
|
toolName = tc.tool_name;
|
|
626
642
|
displayName = tc.display_name;
|
|
@@ -1070,6 +1086,9 @@ function createTurnState(turnId, loopId, opts = {}) {
|
|
|
1070
1086
|
firstTokenMs: null,
|
|
1071
1087
|
streamDurationMs: null,
|
|
1072
1088
|
firstTokenDeliveryMs: null,
|
|
1089
|
+
modelStartedAt: null,
|
|
1090
|
+
modelDurationMs: null,
|
|
1091
|
+
modelStartedAtReported: false,
|
|
1073
1092
|
memoryRefs: opts.memoryRefs ?? null,
|
|
1074
1093
|
parentForkToolCallId: null
|
|
1075
1094
|
};
|
|
@@ -1087,11 +1106,13 @@ function snapshot(state, sequence, status) {
|
|
|
1087
1106
|
tool_calls: [...state.toolCalls],
|
|
1088
1107
|
model: state.model,
|
|
1089
1108
|
usage: state.usage ? { ...state.usage } : null,
|
|
1090
|
-
duration_ms:
|
|
1109
|
+
duration_ms: state.modelDurationMs,
|
|
1091
1110
|
first_token_ms: state.firstTokenMs,
|
|
1092
1111
|
stream_duration_ms: state.streamDurationMs,
|
|
1093
1112
|
first_token_delivery_ms: state.firstTokenDeliveryMs,
|
|
1094
|
-
started_at: new Date(state.startedAt).toISOString(),
|
|
1113
|
+
started_at: state.modelStartedAt ?? new Date(state.startedAt).toISOString(),
|
|
1114
|
+
// 没有 payload 上报时用的是 loop:turn 的浏览器事件时间,标记出来供瀑布区分。
|
|
1115
|
+
has_reported_timing: state.modelStartedAtReported,
|
|
1095
1116
|
context_window: state.contextWindow,
|
|
1096
1117
|
memory_refs: state.memoryRefs,
|
|
1097
1118
|
parent_fork_tool_call_id: state.parentForkToolCallId
|
|
@@ -1312,6 +1333,8 @@ var ClientProjectionBuilder = class {
|
|
|
1312
1333
|
latestTurns = /* @__PURE__ */ new Map();
|
|
1313
1334
|
turnsById = /* @__PURE__ */ new Map();
|
|
1314
1335
|
loopDescriptions = /* @__PURE__ */ new Map();
|
|
1336
|
+
/** loop_name → 正在运行的子智能体起点,agent:end 结算并挂到父工具调用上。 */
|
|
1337
|
+
activeSubagentRuns = /* @__PURE__ */ new Map();
|
|
1315
1338
|
pendingChildPauses = /* @__PURE__ */ new Map();
|
|
1316
1339
|
pendingMemoryRefs = /* @__PURE__ */ new Map();
|
|
1317
1340
|
activeCompactions = /* @__PURE__ */ new Map();
|
|
@@ -1455,6 +1478,7 @@ var ClientProjectionBuilder = class {
|
|
|
1455
1478
|
this.latestTurns.clear();
|
|
1456
1479
|
this.turnsById.clear();
|
|
1457
1480
|
this.loopDescriptions.clear();
|
|
1481
|
+
this.activeSubagentRuns.clear();
|
|
1458
1482
|
this.pendingChildPauses.clear();
|
|
1459
1483
|
this.pendingMemoryRefs.clear();
|
|
1460
1484
|
this.activeCompactions.clear();
|
|
@@ -1596,6 +1620,13 @@ var ClientProjectionBuilder = class {
|
|
|
1596
1620
|
onAgentStart(loopId, payload) {
|
|
1597
1621
|
const description = optStr(payload.description);
|
|
1598
1622
|
if (description) this.loopDescriptions.set(loopId, description);
|
|
1623
|
+
const subagentStartedAt = optStr(payload.started_at);
|
|
1624
|
+
if (subagentStartedAt) {
|
|
1625
|
+
this.activeSubagentRuns.set(loopId, {
|
|
1626
|
+
runId: optStr(payload.run_id) ?? loopId,
|
|
1627
|
+
startedAt: subagentStartedAt
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1599
1630
|
const turn = buildSystemNotificationTurn(
|
|
1600
1631
|
this.nextSeq(),
|
|
1601
1632
|
this.nextTurnId("agent:start"),
|
|
@@ -1797,6 +1828,13 @@ var ClientProjectionBuilder = class {
|
|
|
1797
1828
|
if (typeof payload.stream_duration_ms === "number" && payload.stream_duration_ms >= 0) {
|
|
1798
1829
|
state.streamDurationMs = Math.round(payload.stream_duration_ms);
|
|
1799
1830
|
}
|
|
1831
|
+
if (typeof payload.started_at === "string" && payload.started_at) {
|
|
1832
|
+
state.modelStartedAt = payload.started_at;
|
|
1833
|
+
state.modelStartedAtReported = true;
|
|
1834
|
+
}
|
|
1835
|
+
if (typeof payload.duration_ms === "number" && payload.duration_ms >= 0) {
|
|
1836
|
+
state.modelDurationMs = Math.round(payload.duration_ms);
|
|
1837
|
+
}
|
|
1800
1838
|
}
|
|
1801
1839
|
onToolResultDone(state, loopId, payload) {
|
|
1802
1840
|
const toolCallId = String(payload.tool_call_id ?? "");
|
|
@@ -1807,7 +1845,8 @@ var ClientProjectionBuilder = class {
|
|
|
1807
1845
|
const durationMs = typeof rawDuration === "number" && rawDuration >= 0 ? Math.round(rawDuration) : null;
|
|
1808
1846
|
const ranInParallel = typeof payload.ran_in_parallel === "boolean" ? payload.ran_in_parallel : null;
|
|
1809
1847
|
const sl = sourceLoopFor(state.loopId, this.loopDescriptions);
|
|
1810
|
-
|
|
1848
|
+
const startedAt = typeof payload.started_at === "string" && payload.started_at ? payload.started_at : null;
|
|
1849
|
+
applyToolResult(state, toolCallId, content, status, durationMs, ranInParallel, sl, startedAt);
|
|
1811
1850
|
const isNativeProviderResult = typeof payload.provider === "string" && payload.provider !== "";
|
|
1812
1851
|
if (!isNativeProviderResult && this.shouldFinalizeAfterToolResults(state)) {
|
|
1813
1852
|
return this.finalize(loopId, "completed");
|
|
@@ -1963,6 +2002,7 @@ var ClientProjectionBuilder = class {
|
|
|
1963
2002
|
}
|
|
1964
2003
|
onAgentEnd(state, loopId, payload) {
|
|
1965
2004
|
const ok = payload.ok !== false;
|
|
2005
|
+
this.settleSubagentRun(loopId, payload);
|
|
1966
2006
|
const status = ok ? "done" : "error";
|
|
1967
2007
|
const title = `Agent: ${payload.description ?? payload.skill_id ?? "agent"}`;
|
|
1968
2008
|
const detail = optStr(payload.error);
|
|
@@ -1989,6 +2029,32 @@ var ClientProjectionBuilder = class {
|
|
|
1989
2029
|
);
|
|
1990
2030
|
return [{ kind: "upsert", turn }];
|
|
1991
2031
|
}
|
|
2032
|
+
settleSubagentRun(loopId, payload) {
|
|
2033
|
+
const active = this.activeSubagentRuns.get(loopId);
|
|
2034
|
+
this.activeSubagentRuns.delete(loopId);
|
|
2035
|
+
const parentToolCallId = optStr(payload.parent_fork_tool_call_id);
|
|
2036
|
+
if (!parentToolCallId) return;
|
|
2037
|
+
const rawDuration = payload.run_duration_ms;
|
|
2038
|
+
const durationMs = typeof rawDuration === "number" && rawDuration >= 0 ? Math.round(rawDuration) : null;
|
|
2039
|
+
const rawStatus = optStr(payload.run_status);
|
|
2040
|
+
const status = rawStatus === "failed" || rawStatus === "cancelled" || rawStatus === "paused" || rawStatus === "incomplete" ? rawStatus : payload.ok === false ? "failed" : "completed";
|
|
2041
|
+
const run = {
|
|
2042
|
+
run_id: active?.runId ?? optStr(payload.run_id) ?? loopId,
|
|
2043
|
+
scope: "subagent",
|
|
2044
|
+
loop_id: loopId,
|
|
2045
|
+
started_at: active?.startedAt ?? optStr(payload.run_started_at),
|
|
2046
|
+
duration_ms: durationMs,
|
|
2047
|
+
status
|
|
2048
|
+
};
|
|
2049
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2050
|
+
for (const turn of [...this.latestTurns.values(), ...this.turnsById.values()]) {
|
|
2051
|
+
if (seen.has(turn)) continue;
|
|
2052
|
+
seen.add(turn);
|
|
2053
|
+
const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId);
|
|
2054
|
+
if (!toolCall) continue;
|
|
2055
|
+
toolCall.subagent_runs = [...toolCall.subagent_runs ?? [], run];
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
1992
2058
|
dropIncompleteToolCalls(state) {
|
|
1993
2059
|
if (state.responseDone) return;
|
|
1994
2060
|
state.toolCalls = [];
|
|
@@ -2129,6 +2195,32 @@ function projectHistory(entries) {
|
|
|
2129
2195
|
if (target && duration !== null) target.first_token_delivery_ms = duration;
|
|
2130
2196
|
continue;
|
|
2131
2197
|
}
|
|
2198
|
+
if (kind === "run_timing" && isRecord(entry.data)) {
|
|
2199
|
+
const data = entry.data;
|
|
2200
|
+
if (data.scope === "subagent") {
|
|
2201
|
+
const parentToolCallId = String(data.parent_fork_tool_call_id ?? "");
|
|
2202
|
+
const duration = numberOrNull(data.duration_ms);
|
|
2203
|
+
const rawStatus = String(data.status ?? "completed");
|
|
2204
|
+
const status = rawStatus === "failed" || rawStatus === "cancelled" || rawStatus === "paused" || rawStatus === "incomplete" ? rawStatus : "completed";
|
|
2205
|
+
for (const turn of turns) {
|
|
2206
|
+
const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId);
|
|
2207
|
+
if (!toolCall) continue;
|
|
2208
|
+
toolCall.subagent_runs = [
|
|
2209
|
+
...toolCall.subagent_runs ?? [],
|
|
2210
|
+
{
|
|
2211
|
+
run_id: String(data.run_id ?? ""),
|
|
2212
|
+
scope: "subagent",
|
|
2213
|
+
loop_id: loopId,
|
|
2214
|
+
started_at: typeof data.started_at === "string" ? data.started_at : null,
|
|
2215
|
+
duration_ms: duration,
|
|
2216
|
+
status
|
|
2217
|
+
}
|
|
2218
|
+
];
|
|
2219
|
+
break;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
continue;
|
|
2223
|
+
}
|
|
2132
2224
|
if (kind === "post_chat_followup" && isRecord(entry.data)) {
|
|
2133
2225
|
const assistantEntryId = String(entry.data.assistant_entry_id ?? "");
|
|
2134
2226
|
if (latestRootMessage?.role === "assistant" && latestRootMessage.turn_id === assistantEntryId) {
|
|
@@ -2157,6 +2249,9 @@ function projectHistory(entries) {
|
|
|
2157
2249
|
toolCall.result = message.content ?? "";
|
|
2158
2250
|
const duration = numberOrNull(message._duration_ms);
|
|
2159
2251
|
if (duration !== null) toolCall.duration_ms = duration;
|
|
2252
|
+
if (typeof message._started_at === "string") {
|
|
2253
|
+
toolCall.started_at = message._started_at;
|
|
2254
|
+
}
|
|
2160
2255
|
if (message._ran_in_parallel === true) toolCall.ran_in_parallel = true;
|
|
2161
2256
|
owner.blocks.push({
|
|
2162
2257
|
type: "tool_result",
|
|
@@ -2181,10 +2276,12 @@ function projectHistory(entries) {
|
|
|
2181
2276
|
tool_calls: toolCalls,
|
|
2182
2277
|
model: stringOrNull(message.model),
|
|
2183
2278
|
usage: isRecord(message._usage) ? { ...message._usage } : null,
|
|
2184
|
-
|
|
2279
|
+
// 模型请求区间来自持久化字段;旧会话缺失时为 null,不用落盘时刻冒充(#2581 A1)。
|
|
2280
|
+
duration_ms: numberOrNull(message._duration_ms),
|
|
2185
2281
|
first_token_ms: numberOrNull(message._first_token_ms),
|
|
2186
2282
|
stream_duration_ms: numberOrNull(message._stream_duration_ms),
|
|
2187
|
-
started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0,
|
|
2283
|
+
started_at: typeof message._started_at === "string" ? message._started_at : typeof entry.timestamp === "string" ? entry.timestamp : void 0,
|
|
2284
|
+
has_reported_timing: typeof message._started_at === "string",
|
|
2188
2285
|
// fork 子会话的父锚点:历史里落在消息级 _parent_fork_tool_call_id。丢掉它,
|
|
2189
2286
|
// 刷新后工作流步骤 fork 就配不回 workflow:run 工具调用(普通 Agent fork 有
|
|
2190
2287
|
// root Agent 工具调用兜底配对,工作流 fork 没有,子智能体卡会整体消失)。
|
|
@@ -2201,10 +2298,15 @@ function projectHistory(entries) {
|
|
|
2201
2298
|
previousTurn.status = turn.status;
|
|
2202
2299
|
previousTurn.model = turn.model ?? previousTurn.model;
|
|
2203
2300
|
previousTurn.usage = turn.usage ?? previousTurn.usage;
|
|
2204
|
-
previousTurn.duration_ms = turn.duration_ms
|
|
2301
|
+
if (turn.duration_ms) previousTurn.duration_ms = turn.duration_ms;
|
|
2205
2302
|
previousTurn.first_token_ms = turn.first_token_ms ?? previousTurn.first_token_ms;
|
|
2206
2303
|
previousTurn.stream_duration_ms = turn.stream_duration_ms ?? previousTurn.stream_duration_ms;
|
|
2207
|
-
if (turn.
|
|
2304
|
+
if (turn.has_reported_timing) {
|
|
2305
|
+
previousTurn.started_at = turn.started_at;
|
|
2306
|
+
previousTurn.has_reported_timing = true;
|
|
2307
|
+
} else if (!previousTurn.has_reported_timing) {
|
|
2308
|
+
previousTurn.started_at = previousTurn.started_at ?? turn.started_at;
|
|
2309
|
+
}
|
|
2208
2310
|
previousTurn.id = turn.id;
|
|
2209
2311
|
previousTurn.turn_id = turn.turn_id;
|
|
2210
2312
|
if (isNativeToolEntry) nativeToolTurns.add(previousTurn);
|
|
@@ -2482,9 +2584,6 @@ function markerTurn(id, sequence, loopId, type3, content, toolCallId = null) {
|
|
|
2482
2584
|
function stringOrNull(value) {
|
|
2483
2585
|
return typeof value === "string" ? value : null;
|
|
2484
2586
|
}
|
|
2485
|
-
function numberOrZero(value) {
|
|
2486
|
-
return typeof value === "number" ? value : 0;
|
|
2487
|
-
}
|
|
2488
2587
|
function numberOrNull(value) {
|
|
2489
2588
|
return typeof value === "number" && value >= 0 ? value : null;
|
|
2490
2589
|
}
|
|
@@ -2517,7 +2616,7 @@ function toCreateSessionPayload(request) {
|
|
|
2517
2616
|
...request.runtime_type ? { runtime_type: request.runtime_type } : {},
|
|
2518
2617
|
...request.daemon_id ? { daemon_id: request.daemon_id } : {},
|
|
2519
2618
|
...request.agent_runtime_id ? { agent_runtime_id: request.agent_runtime_id } : {},
|
|
2520
|
-
...request.
|
|
2619
|
+
...request.chat_group_id ? { chat_group_id: request.chat_group_id } : {}
|
|
2521
2620
|
};
|
|
2522
2621
|
}
|
|
2523
2622
|
var builtinSolutionIds = /* @__PURE__ */ new Set([
|
|
@@ -2602,6 +2701,18 @@ var SessionsResource = class {
|
|
|
2602
2701
|
sessionPluginIconUrl(sessionId, name) {
|
|
2603
2702
|
return this.client.buildAuthedUrl(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/icon`);
|
|
2604
2703
|
}
|
|
2704
|
+
/**
|
|
2705
|
+
* 准备一个插件的配置:把包准备好并读出用户的配置契约,**不启用**它。
|
|
2706
|
+
*
|
|
2707
|
+
* 开启插件前必须先走这一步:缺配置时用户只会看到配置表单,服务端不会先把
|
|
2708
|
+
* active 持久化成 true 再靠补偿关掉。它不修改会话的插件选择、不连接 MCP。
|
|
2709
|
+
*/
|
|
2710
|
+
prepareSessionPluginConfig(sessionId, name, init) {
|
|
2711
|
+
return this.client.jsonFromInit(
|
|
2712
|
+
`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}:prepare-config`,
|
|
2713
|
+
{ method: "POST", ...init }
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2605
2716
|
/**
|
|
2606
2717
|
* Read a plugin's configuration contract and the user's stored values.
|
|
2607
2718
|
*
|
|
@@ -2717,7 +2828,7 @@ var SessionsResource = class {
|
|
|
2717
2828
|
solution_id,
|
|
2718
2829
|
solution_registry_id,
|
|
2719
2830
|
q,
|
|
2720
|
-
|
|
2831
|
+
chat_group_id
|
|
2721
2832
|
}) {
|
|
2722
2833
|
const searchParams = new URLSearchParams();
|
|
2723
2834
|
searchParams.set("limit", String(limit));
|
|
@@ -2730,7 +2841,7 @@ var SessionsResource = class {
|
|
|
2730
2841
|
}
|
|
2731
2842
|
const trimmedQuery = q?.trim();
|
|
2732
2843
|
if (trimmedQuery) searchParams.set("q", trimmedQuery);
|
|
2733
|
-
if (
|
|
2844
|
+
if (chat_group_id) searchParams.set("chat_group_id", chat_group_id);
|
|
2734
2845
|
return this.client.json("GET", `/api/sessions?${searchParams.toString()}`);
|
|
2735
2846
|
}
|
|
2736
2847
|
async listSessions(template_id_prefix, solution_id) {
|
|
@@ -3115,23 +3226,48 @@ function profileToCreateSessionRequest(profile) {
|
|
|
3115
3226
|
};
|
|
3116
3227
|
}
|
|
3117
3228
|
|
|
3118
|
-
// src/resources/
|
|
3119
|
-
var
|
|
3229
|
+
// src/resources/plugins.ts
|
|
3230
|
+
var PluginsResource = class {
|
|
3231
|
+
constructor(client) {
|
|
3232
|
+
this.client = client;
|
|
3233
|
+
}
|
|
3234
|
+
client;
|
|
3235
|
+
/**
|
|
3236
|
+
* 列出当前用户安装的插件及其展示信息。
|
|
3237
|
+
*
|
|
3238
|
+
* 服务端可能为了补齐名称/图标惰性获取包内容,但绝不激活插件、不连 MCP;
|
|
3239
|
+
* 单个插件的展示信息读不出来只会降级成占位,不会让整份目录失败。
|
|
3240
|
+
*/
|
|
3241
|
+
catalog(init) {
|
|
3242
|
+
return this.client.jsonFromInit("/api/plugins/catalog", init);
|
|
3243
|
+
}
|
|
3244
|
+
/** 取一个插件的包内图标字节(用户级,不需要会话)。 */
|
|
3245
|
+
fetchIcon(name) {
|
|
3246
|
+
return this.client.blob("GET", `/api/plugins/${encodeURIComponent(name)}/icon`);
|
|
3247
|
+
}
|
|
3248
|
+
/** 带凭据的图标地址;能直接用 blob URL 的地方优先用 `fetchIcon`。 */
|
|
3249
|
+
iconUrl(name) {
|
|
3250
|
+
return this.client.buildAuthedUrl(`/api/plugins/${encodeURIComponent(name)}/icon`);
|
|
3251
|
+
}
|
|
3252
|
+
};
|
|
3253
|
+
|
|
3254
|
+
// src/resources/chat-groups.ts
|
|
3255
|
+
var ChatGroupsResource = class {
|
|
3120
3256
|
constructor(client) {
|
|
3121
3257
|
this.client = client;
|
|
3122
3258
|
}
|
|
3123
3259
|
client;
|
|
3124
3260
|
list() {
|
|
3125
|
-
return this.client.json("GET", "/api/chat-
|
|
3261
|
+
return this.client.json("GET", "/api/chat-groups");
|
|
3126
3262
|
}
|
|
3127
3263
|
create(payload) {
|
|
3128
|
-
return this.client.json("POST", "/api/chat-
|
|
3264
|
+
return this.client.json("POST", "/api/chat-groups", payload);
|
|
3129
3265
|
}
|
|
3130
|
-
update(
|
|
3131
|
-
return this.client.json("PATCH", `/api/chat-
|
|
3266
|
+
update(groupId, payload) {
|
|
3267
|
+
return this.client.json("PATCH", `/api/chat-groups/${encodeURIComponent(groupId)}`, payload);
|
|
3132
3268
|
}
|
|
3133
|
-
delete(
|
|
3134
|
-
return this.client.json("DELETE", `/api/chat-
|
|
3269
|
+
delete(groupId) {
|
|
3270
|
+
return this.client.json("DELETE", `/api/chat-groups/${encodeURIComponent(groupId)}`);
|
|
3135
3271
|
}
|
|
3136
3272
|
};
|
|
3137
3273
|
|
|
@@ -5934,7 +6070,9 @@ var BladeClient = class {
|
|
|
5934
6070
|
computers;
|
|
5935
6071
|
models;
|
|
5936
6072
|
sessions;
|
|
5937
|
-
|
|
6073
|
+
/** 按用户读取的插件目录与图标;没有会话时也能用。 */
|
|
6074
|
+
plugins;
|
|
6075
|
+
chatGroups;
|
|
5938
6076
|
/**
|
|
5939
6077
|
* 全站访问统计:匿名读写,不带 bearer 也不触发登录刷新。
|
|
5940
6078
|
* 只有内置 Web 的同源页面使用,第三方宿主页面不会被自动统计。
|
|
@@ -5952,7 +6090,8 @@ var BladeClient = class {
|
|
|
5952
6090
|
this.computers = new ComputersResource(this);
|
|
5953
6091
|
this.models = new ModelsResource(this);
|
|
5954
6092
|
this.sessions = new SessionsResource(this);
|
|
5955
|
-
this.
|
|
6093
|
+
this.plugins = new PluginsResource(this);
|
|
6094
|
+
this.chatGroups = new ChatGroupsResource(this);
|
|
5956
6095
|
this.siteVisits = new SiteVisitsResource(this);
|
|
5957
6096
|
this.hub = new SessionHub(this);
|
|
5958
6097
|
if (this.options.token === void 0) {
|
|
@@ -6421,7 +6560,7 @@ function resolveServiceUrl(endpoints, name, path = "") {
|
|
|
6421
6560
|
|
|
6422
6561
|
// src/version.ts
|
|
6423
6562
|
var SDK_NAME = "agent-client";
|
|
6424
|
-
var SDK_VERSION = true ? "2610.0.0-beta.
|
|
6563
|
+
var SDK_VERSION = true ? "2610.0.0-beta.55" : "1.1.1";
|
|
6425
6564
|
|
|
6426
6565
|
// src/commands/protocol.ts
|
|
6427
6566
|
function isCommandEnvelope(value) {
|
|
@@ -6526,7 +6665,7 @@ export {
|
|
|
6526
6665
|
AuthBusyReconnect,
|
|
6527
6666
|
BladeApiError,
|
|
6528
6667
|
BladeClient,
|
|
6529
|
-
|
|
6668
|
+
ChatGroupsResource,
|
|
6530
6669
|
ClientProjectionBuilder,
|
|
6531
6670
|
ComputersResource,
|
|
6532
6671
|
DEFAULT_REPLAY_SPEED,
|
|
@@ -6534,6 +6673,7 @@ export {
|
|
|
6534
6673
|
EMPTY_SESSION_QUEUE,
|
|
6535
6674
|
LayoutType,
|
|
6536
6675
|
ModelsResource,
|
|
6676
|
+
PluginsResource,
|
|
6537
6677
|
PollingBackoff,
|
|
6538
6678
|
SDK_NAME,
|
|
6539
6679
|
SDK_VERSION,
|