@mtreeai/msapling-cli 2.3.6-beta.47 → 2.3.6-beta.48
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/dist/index.js +102 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1032,6 +1032,47 @@ var init_src = __esm({
|
|
|
1032
1032
|
body: JSON.stringify({ query, max_results: maxResults })
|
|
1033
1033
|
});
|
|
1034
1034
|
}
|
|
1035
|
+
/**
|
|
1036
|
+
* CLI-LOOP-01: cached backend capability map (from GET /chat/health). `null`
|
|
1037
|
+
* until first probed. Cached for the client's lifetime — capabilities are a
|
|
1038
|
+
* deploy-time property of the backend, so a single probe per session suffices.
|
|
1039
|
+
*/
|
|
1040
|
+
_capabilities = null;
|
|
1041
|
+
_capabilitiesProbe = null;
|
|
1042
|
+
/**
|
|
1043
|
+
* CLI-LOOP-01: fetch (and cache) the backend capability map from
|
|
1044
|
+
* GET /chat/health. Returns an empty object when the backend is older / the
|
|
1045
|
+
* probe fails, so callers degrade to legacy behavior rather than throwing.
|
|
1046
|
+
*
|
|
1047
|
+
* Concurrent callers share a single in-flight probe.
|
|
1048
|
+
*/
|
|
1049
|
+
async getCapabilities(force = false) {
|
|
1050
|
+
if (this._capabilities && !force) return this._capabilities;
|
|
1051
|
+
if (this._capabilitiesProbe && !force) return this._capabilitiesProbe;
|
|
1052
|
+
this._capabilitiesProbe = (async () => {
|
|
1053
|
+
try {
|
|
1054
|
+
const data = await this.request("/api/chat/health");
|
|
1055
|
+
const caps = data && typeof data === "object" && data.capabilities && typeof data.capabilities === "object" ? data.capabilities : {};
|
|
1056
|
+
this._capabilities = caps;
|
|
1057
|
+
return caps;
|
|
1058
|
+
} catch {
|
|
1059
|
+
this._capabilities = {};
|
|
1060
|
+
return this._capabilities;
|
|
1061
|
+
} finally {
|
|
1062
|
+
this._capabilitiesProbe = null;
|
|
1063
|
+
}
|
|
1064
|
+
})();
|
|
1065
|
+
return this._capabilitiesProbe;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* CLI-LOOP-01: convenience — does the backend accept the additive structured
|
|
1069
|
+
* `tool_results` array (native parallel multi-tool-use)? When false the Agent
|
|
1070
|
+
* loop uses the legacy `[TOOL_RESULT]`-per-prompt path.
|
|
1071
|
+
*/
|
|
1072
|
+
async supportsStructuredToolResults() {
|
|
1073
|
+
const caps = await this.getCapabilities();
|
|
1074
|
+
return caps.structured_tool_results === true;
|
|
1075
|
+
}
|
|
1035
1076
|
async getHistory(chatId) {
|
|
1036
1077
|
const data = await this.request(`/api/projects/chat/${chatId}/history`);
|
|
1037
1078
|
return data.messages.map((m) => ({
|
|
@@ -7407,8 +7448,15 @@ var init_Agent = __esm({
|
|
|
7407
7448
|
}
|
|
7408
7449
|
const config = await this.getProjectConfig();
|
|
7409
7450
|
const MAX_WORKER_TURN_DEPTH = 25;
|
|
7451
|
+
let structuredToolResults = false;
|
|
7452
|
+
try {
|
|
7453
|
+
structuredToolResults = await this.client.supportsStructuredToolResults();
|
|
7454
|
+
} catch {
|
|
7455
|
+
structuredToolResults = false;
|
|
7456
|
+
}
|
|
7410
7457
|
const queue = [prompt4];
|
|
7411
7458
|
let rounds = 0;
|
|
7459
|
+
let toolCallSeq = 0;
|
|
7412
7460
|
let streamUsage = null;
|
|
7413
7461
|
while (queue.length > 0 && rounds < MAX_WORKER_TURN_DEPTH) {
|
|
7414
7462
|
if (this.contextBudget.needsCompaction() && queue.length > 0) {
|
|
@@ -7452,14 +7500,25 @@ var init_Agent = __esm({
|
|
|
7452
7500
|
this.contextBudget.reset();
|
|
7453
7501
|
if (compactionSummary) {
|
|
7454
7502
|
const next = queue[0];
|
|
7455
|
-
|
|
7503
|
+
if (typeof next === "string") {
|
|
7504
|
+
queue[0] = `[CONTEXT_SUMMARY]: ${compactionSummary}
|
|
7456
7505
|
|
|
7457
7506
|
${next}`;
|
|
7507
|
+
} else {
|
|
7508
|
+
queue[0] = {
|
|
7509
|
+
...next,
|
|
7510
|
+
prompt: `[CONTEXT_SUMMARY]: ${compactionSummary}
|
|
7511
|
+
|
|
7512
|
+
${next.prompt}`
|
|
7513
|
+
};
|
|
7514
|
+
}
|
|
7458
7515
|
}
|
|
7459
7516
|
continue;
|
|
7460
7517
|
}
|
|
7461
|
-
const
|
|
7518
|
+
const currentItem = queue.shift();
|
|
7462
7519
|
rounds++;
|
|
7520
|
+
const currentPrompt = typeof currentItem === "string" ? currentItem : currentItem.prompt;
|
|
7521
|
+
const currentToolResults = typeof currentItem === "string" ? void 0 : currentItem.toolResults;
|
|
7463
7522
|
const stream = this.chatWithFallback(
|
|
7464
7523
|
{
|
|
7465
7524
|
chat_id: chatId,
|
|
@@ -7468,11 +7527,16 @@ ${next}`;
|
|
|
7468
7527
|
tools: this.executor.getToolSchemas(),
|
|
7469
7528
|
project_root: this.projectRoot,
|
|
7470
7529
|
mode: this.executor.getMode(),
|
|
7530
|
+
// CLI-LOOP-01: carry the concurrently-executed tool_results from the
|
|
7531
|
+
// previous turn as a structured batch. Only set in the capability-
|
|
7532
|
+
// enabled path; absent => backend sees the legacy single-prompt turn.
|
|
7533
|
+
...currentToolResults && currentToolResults.length > 0 ? { tool_results: currentToolResults } : {},
|
|
7471
7534
|
...config.combined ? { project_context: config.combined } : {}
|
|
7472
7535
|
},
|
|
7473
7536
|
chatId,
|
|
7474
7537
|
currentPrompt
|
|
7475
7538
|
);
|
|
7539
|
+
const pendingToolCalls = [];
|
|
7476
7540
|
for await (const chunk of stream) {
|
|
7477
7541
|
if (chunk.content) {
|
|
7478
7542
|
onContent(chunk.content);
|
|
@@ -7489,11 +7553,39 @@ ${next}`;
|
|
|
7489
7553
|
});
|
|
7490
7554
|
}
|
|
7491
7555
|
if (chunk.tool_use) {
|
|
7492
|
-
const
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7556
|
+
const id = chunk.tool_use.id ?? `call_${rounds}_${toolCallSeq++}`;
|
|
7557
|
+
pendingToolCalls.push({ id, name: chunk.tool_use.name, args: chunk.tool_use.args });
|
|
7558
|
+
}
|
|
7559
|
+
}
|
|
7560
|
+
if (pendingToolCalls.length === 0) {
|
|
7561
|
+
continue;
|
|
7562
|
+
}
|
|
7563
|
+
if (structuredToolResults) {
|
|
7564
|
+
const toolResults = await Promise.all(
|
|
7565
|
+
pendingToolCalls.map(async (call) => {
|
|
7566
|
+
try {
|
|
7567
|
+
const result = await this.executor.execute(call.name, call.args, this.projectRoot);
|
|
7568
|
+
const redactedContent = SafetyGuard.redact(result.content);
|
|
7569
|
+
return {
|
|
7570
|
+
tool_use_id: call.id,
|
|
7571
|
+
name: call.name,
|
|
7572
|
+
content: redactedContent,
|
|
7573
|
+
is_error: !!result.isError
|
|
7574
|
+
};
|
|
7575
|
+
} catch (e) {
|
|
7576
|
+
return {
|
|
7577
|
+
tool_use_id: call.id,
|
|
7578
|
+
name: call.name,
|
|
7579
|
+
content: SafetyGuard.redact(`Tool execution failed: ${e?.message ?? String(e)}`),
|
|
7580
|
+
is_error: true
|
|
7581
|
+
};
|
|
7582
|
+
}
|
|
7583
|
+
})
|
|
7584
|
+
);
|
|
7585
|
+
queue.push({ prompt: "", toolResults });
|
|
7586
|
+
} else {
|
|
7587
|
+
for (const call of pendingToolCalls) {
|
|
7588
|
+
const result = await this.executor.execute(call.name, call.args, this.projectRoot);
|
|
7497
7589
|
const redactedContent = SafetyGuard.redact(result.content);
|
|
7498
7590
|
const redactedResult = { ...result, content: redactedContent };
|
|
7499
7591
|
queue.push(`[TOOL_RESULT]: ${JSON.stringify(redactedResult)}`);
|
|
@@ -12114,7 +12206,7 @@ var init_version = __esm({
|
|
|
12114
12206
|
description: "Show version information for CLI and core packages",
|
|
12115
12207
|
category: "debug",
|
|
12116
12208
|
handler: async (_args, context) => {
|
|
12117
|
-
const cliVersion = true ? "2.3.6-beta.
|
|
12209
|
+
const cliVersion = true ? "2.3.6-beta.48" : "(dev)";
|
|
12118
12210
|
const coreVersion = true ? "2.3.6-beta.43" : "(dev)";
|
|
12119
12211
|
const runtime = process.version;
|
|
12120
12212
|
context.addMessage("system", "MSapling Version Info");
|
|
@@ -12123,7 +12215,7 @@ var init_version = __esm({
|
|
|
12123
12215
|
context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
|
|
12124
12216
|
context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
|
|
12125
12217
|
try {
|
|
12126
|
-
const ts = "2026-06-20T08:
|
|
12218
|
+
const ts = "2026-06-20T08:17:10.331Z";
|
|
12127
12219
|
if (ts && ts !== "__BUILD_TIMESTAMP__") {
|
|
12128
12220
|
context.addMessage("system", row2("Build Timestamp", ts));
|
|
12129
12221
|
}
|
|
@@ -17917,7 +18009,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
17917
18009
|
var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
17918
18010
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
17919
18011
|
"\u25CF MSapling CLI v",
|
|
17920
|
-
"2.3.6-beta.
|
|
18012
|
+
"2.3.6-beta.48"
|
|
17921
18013
|
] }),
|
|
17922
18014
|
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
|
|
17923
18015
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtreeai/msapling-cli",
|
|
3
|
-
"version": "2.3.6-beta.
|
|
3
|
+
"version": "2.3.6-beta.48",
|
|
4
4
|
"description": "MSapling CLI — React/Ink terminal client for the MSapling backend (chat, projects, MDrive, agent tools). Proprietary; redistribution prohibited.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "MSapling Team",
|