clay-server 3.4.0 → 3.5.0-beta.1
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.
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
var yoke = require("./yoke");
|
|
2
2
|
var contextBuilder = require("./session-handoff-context");
|
|
3
|
+
var sessionHandoffMcp = require("./session-handoff-mcp-server");
|
|
4
|
+
|
|
5
|
+
var MAX_HANDOFF_CHAIN_DEPTH = 5;
|
|
6
|
+
|
|
7
|
+
function toolResult(text) {
|
|
8
|
+
return Promise.resolve({ content: [{ type: "text", text: text }] });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function toolError(message) {
|
|
12
|
+
return Promise.resolve({
|
|
13
|
+
content: [{ type: "text", text: "Error: " + message }],
|
|
14
|
+
isError: true,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
3
17
|
|
|
4
18
|
function hasUserContext(session) {
|
|
5
19
|
var history = (session && session.history) || [];
|
|
@@ -38,7 +52,7 @@ function attachSessionHandoff(ctx) {
|
|
|
38
52
|
}
|
|
39
53
|
var ownerId = ws._clayUser && ctx.usersModule.isMultiUser() ? ws._clayUser.id : null;
|
|
40
54
|
if ((source.ownerId || null) !== ownerId) throw new Error("Session access denied.");
|
|
41
|
-
return linuxUser;
|
|
55
|
+
return { linuxUser: linuxUser, vendorInfo: vendorInfo };
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
function quietRecord(session, entry) {
|
|
@@ -50,9 +64,9 @@ function attachSessionHandoff(ctx) {
|
|
|
50
64
|
var source = sm.sessions.get(ws._clayActiveSession) || null;
|
|
51
65
|
var targetVendor = typeof msg.targetVendor === "string" ? msg.targetVendor.trim() : "";
|
|
52
66
|
var targetModel = typeof msg.model === "string" ? msg.model.trim() : "";
|
|
53
|
-
var
|
|
67
|
+
var validation;
|
|
54
68
|
try {
|
|
55
|
-
|
|
69
|
+
validation = validate(ws, source, targetVendor);
|
|
56
70
|
} catch (err) {
|
|
57
71
|
sendResult(ws, false, { error: err.message || String(err) });
|
|
58
72
|
return;
|
|
@@ -102,6 +116,7 @@ function attachSessionHandoff(ctx) {
|
|
|
102
116
|
cwd: ctx.cwd,
|
|
103
117
|
source: source,
|
|
104
118
|
targetVendor: targetVendor,
|
|
119
|
+
sourceReadTool: (validation.vendorInfo || {}).sessionBoundTools !== false,
|
|
105
120
|
});
|
|
106
121
|
target.isProcessing = true;
|
|
107
122
|
target.lastActivity = Date.now();
|
|
@@ -128,7 +143,7 @@ function attachSessionHandoff(ctx) {
|
|
|
128
143
|
target._queryStartTs = Date.now();
|
|
129
144
|
var startPromise;
|
|
130
145
|
try {
|
|
131
|
-
startPromise = sdk.startQuery(target, prompt, undefined, linuxUser);
|
|
146
|
+
startPromise = sdk.startQuery(target, prompt, undefined, validation.linuxUser);
|
|
132
147
|
} catch (err) {
|
|
133
148
|
failStart(err);
|
|
134
149
|
return;
|
|
@@ -153,7 +168,111 @@ function attachSessionHandoff(ctx) {
|
|
|
153
168
|
return false;
|
|
154
169
|
}
|
|
155
170
|
|
|
156
|
-
|
|
171
|
+
function resolveSourceChain(boundSession) {
|
|
172
|
+
var chain = [];
|
|
173
|
+
var visited = new Set();
|
|
174
|
+
var sourceSessionId = boundSession.handoff.sourceSessionId;
|
|
175
|
+
var ownerId = boundSession.ownerId || null;
|
|
176
|
+
for (var depth = 0; depth < MAX_HANDOFF_CHAIN_DEPTH; depth++) {
|
|
177
|
+
var visitKey = String(sourceSessionId);
|
|
178
|
+
if (visited.has(visitKey)) break;
|
|
179
|
+
visited.add(visitKey);
|
|
180
|
+
var source = sm.sessions.get(sourceSessionId);
|
|
181
|
+
if (!source) return { error: "Source session was not found: " + sourceSessionId };
|
|
182
|
+
if ((source.ownerId || null) !== ownerId) return { error: "Source session owner does not match this session" };
|
|
183
|
+
chain.push(source);
|
|
184
|
+
if (!source.handoff || source.handoff.sourceSessionId === undefined || source.handoff.sourceSessionId === null) break;
|
|
185
|
+
sourceSessionId = source.handoff.sourceSessionId;
|
|
186
|
+
}
|
|
187
|
+
return { chain: chain };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function findSource(chain, requestedId) {
|
|
191
|
+
if (requestedId === undefined || requestedId === null || requestedId === "") return chain[0] || null;
|
|
192
|
+
for (var i = 0; i < chain.length; i++) {
|
|
193
|
+
if (String(chain[i].localId) === String(requestedId)) return chain[i];
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function boundedInteger(value, fallback, min, max) {
|
|
199
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
200
|
+
return Math.min(max, Math.max(min, Math.floor(value)));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function formatHistory(source, args) {
|
|
204
|
+
var history = Array.isArray(source.history) ? source.history : [];
|
|
205
|
+
var limit = boundedInteger(args.limit, 30, 1, 100);
|
|
206
|
+
var offset = typeof args.offset === "number" && Number.isFinite(args.offset)
|
|
207
|
+
? boundedInteger(args.offset, 0, 0, history.length)
|
|
208
|
+
: Math.max(0, history.length - limit);
|
|
209
|
+
var slice = history.slice(offset, offset + limit);
|
|
210
|
+
var end = offset + slice.length;
|
|
211
|
+
var out = [];
|
|
212
|
+
out.push("# " + (source.title || "Untitled session") + " — " + (source.vendor || "unknown") + "/" + source.localId);
|
|
213
|
+
out.push("Showing entries " + (slice.length ? offset + 1 : 0) + "-" + end + " of " + history.length + "\n");
|
|
214
|
+
for (var i = 0; i < slice.length; i++) {
|
|
215
|
+
var entry = slice[i];
|
|
216
|
+
if (!entry) continue;
|
|
217
|
+
var label;
|
|
218
|
+
var text = "";
|
|
219
|
+
if (entry.type === "user_message") {
|
|
220
|
+
label = "USER";
|
|
221
|
+
text = entry.text || "";
|
|
222
|
+
} else if (entry.type === "delta") {
|
|
223
|
+
label = "ASSISTANT";
|
|
224
|
+
text = entry.text || "";
|
|
225
|
+
} else if (entry.type === "tool_executing" || entry.type === "tool_result") {
|
|
226
|
+
label = "TOOL";
|
|
227
|
+
text = (entry.name || "") + (entry.input ? " " + JSON.stringify(entry.input).substring(0, 120) : "");
|
|
228
|
+
} else {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (text.length > 800) text = text.substring(0, 800) + "...";
|
|
232
|
+
out.push("[" + label + "] " + text);
|
|
233
|
+
}
|
|
234
|
+
return out.join("\n");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function readHandoffSource(args, boundSession) {
|
|
238
|
+
if (!boundSession) return toolError("read_handoff_source requires a session-bound tool server");
|
|
239
|
+
if (!boundSession.handoff) return toolError("this session does not have a handoff source");
|
|
240
|
+
var resolved = resolveSourceChain(boundSession);
|
|
241
|
+
if (resolved.error) return toolError(resolved.error);
|
|
242
|
+
var source = findSource(resolved.chain, args.sourceSessionId);
|
|
243
|
+
if (!source) return toolError("sourceSessionId is not in this session's handoff chain");
|
|
244
|
+
return toolResult(formatHistory(source, args));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function getToolDefs(boundSession) {
|
|
248
|
+
if (ctx.isMate) return [];
|
|
249
|
+
if (boundSession && !boundSession.handoff) return [];
|
|
250
|
+
return sessionHandoffMcp.getToolDefs({
|
|
251
|
+
read: function (args) { return readHandoffSource(args, boundSession || null); },
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function createMcpServer(adapter, boundSession) {
|
|
256
|
+
if (ctx.isMate || !adapter || typeof adapter.createToolServer !== "function") return null;
|
|
257
|
+
var tools = getToolDefs(boundSession || null);
|
|
258
|
+
if (tools.length === 0) return null;
|
|
259
|
+
return adapter.createToolServer({
|
|
260
|
+
name: "clay-handoff",
|
|
261
|
+
version: "1.0.0",
|
|
262
|
+
tools: tools,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getSystemPrompt() {
|
|
267
|
+
return "";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
createMcpServer: createMcpServer,
|
|
272
|
+
getSystemPrompt: getSystemPrompt,
|
|
273
|
+
getToolDefs: getToolDefs,
|
|
274
|
+
handleMessage: handleMessage,
|
|
275
|
+
};
|
|
157
276
|
}
|
|
158
277
|
|
|
159
278
|
module.exports = {
|
package/lib/project.js
CHANGED
|
@@ -620,6 +620,16 @@ function createProjectContext(opts) {
|
|
|
620
620
|
}
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
// Session-bound access to the source of a handoff (main projects only).
|
|
624
|
+
if (!isMate) {
|
|
625
|
+
try {
|
|
626
|
+
var sessionHandoffMcpConfig = _sessionHandoff.createMcpServer(adapter);
|
|
627
|
+
if (sessionHandoffMcpConfig) servers[sessionHandoffMcpConfig.name || "clay-handoff"] = sessionHandoffMcpConfig;
|
|
628
|
+
} catch (e) {
|
|
629
|
+
console.error("[project] Failed to create session handoff MCP server:", e.message);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
623
633
|
// Explicit agent signal for user-requested Markdown presentation.
|
|
624
634
|
if (!isMate) {
|
|
625
635
|
try {
|
|
@@ -780,7 +790,7 @@ function createProjectContext(opts) {
|
|
|
780
790
|
// clay-email -> only when the user has an account or server SMTP
|
|
781
791
|
//
|
|
782
792
|
// forSession (optional): the session whose query these servers are mounted
|
|
783
|
-
// into. Session, notes, and document tools must know their caller, so they
|
|
793
|
+
// into. Session, notes, handoff, and document tools must know their caller, so they
|
|
784
794
|
// are re-instantiated bound to that session; static instances only serve
|
|
785
795
|
// descriptor listing and fail closed on calls.
|
|
786
796
|
function getLocalMcpServers(forSession) {
|
|
@@ -812,6 +822,15 @@ function createProjectContext(opts) {
|
|
|
812
822
|
}
|
|
813
823
|
continue;
|
|
814
824
|
}
|
|
825
|
+
if (name === "clay-handoff" && forSession) {
|
|
826
|
+
try {
|
|
827
|
+
var boundHandoff = _sessionHandoff.createMcpServer(adapter, forSession);
|
|
828
|
+
if (boundHandoff) { filtered[name] = boundHandoff; hasAny = true; }
|
|
829
|
+
} catch (e) {
|
|
830
|
+
console.error("[project] Failed to bind session handoff MCP server:", e.message);
|
|
831
|
+
}
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
815
834
|
if (name === "clay-documents" && forSession) {
|
|
816
835
|
try {
|
|
817
836
|
var boundDocuments = _sessionDocument.createMcpServer(adapter, forSession);
|
|
@@ -879,12 +898,14 @@ function createProjectContext(opts) {
|
|
|
879
898
|
return composeSystemPrompts([
|
|
880
899
|
_sessionPair.getSystemPrompt(session),
|
|
881
900
|
_sessionNotes.getSystemPrompt(session),
|
|
901
|
+
_sessionHandoff.getSystemPrompt(session),
|
|
882
902
|
_sessionDocument.getSystemPrompt(session),
|
|
883
903
|
]);
|
|
884
904
|
},
|
|
885
905
|
getSessionToolDefs: function (session) {
|
|
886
906
|
return _sessionPair.getToolDefs(session)
|
|
887
907
|
.concat(_sessionNotes.getToolDefs(session))
|
|
908
|
+
.concat(_sessionHandoff.getToolDefs(session))
|
|
888
909
|
.concat(_sessionDocument.getToolDefs(session));
|
|
889
910
|
},
|
|
890
911
|
});
|
|
@@ -1489,6 +1510,15 @@ function createProjectContext(opts) {
|
|
|
1489
1510
|
inputSchema: normalizeToolSchema(noteTools[nti].inputSchema),
|
|
1490
1511
|
});
|
|
1491
1512
|
}
|
|
1513
|
+
var handoffTools = _sessionHandoff.getToolDefs(boundSession);
|
|
1514
|
+
for (var hti = 0; hti < handoffTools.length; hti++) {
|
|
1515
|
+
tools.push({
|
|
1516
|
+
server: "clay-handoff",
|
|
1517
|
+
name: handoffTools[hti].name,
|
|
1518
|
+
description: handoffTools[hti].description || handoffTools[hti].name,
|
|
1519
|
+
inputSchema: normalizeToolSchema(handoffTools[hti].inputSchema),
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1492
1522
|
var documentTools = _sessionDocument.getToolDefs(boundSession);
|
|
1493
1523
|
for (var dti = 0; dti < documentTools.length; dti++) {
|
|
1494
1524
|
tools.push({
|
|
@@ -1509,7 +1539,7 @@ function createProjectContext(opts) {
|
|
|
1509
1539
|
if (localMcp) {
|
|
1510
1540
|
var inAppNames = Object.keys(localMcp);
|
|
1511
1541
|
for (var i = 0; i < inAppNames.length; i++) {
|
|
1512
|
-
if (inAppNames[i] === "clay-sessions" || inAppNames[i] === "clay-notes" || inAppNames[i] === "clay-documents") continue;
|
|
1542
|
+
if (inAppNames[i] === "clay-sessions" || inAppNames[i] === "clay-notes" || inAppNames[i] === "clay-handoff" || inAppNames[i] === "clay-documents") continue;
|
|
1513
1543
|
extractServerTools(inAppNames[i], localMcp[inAppNames[i]]);
|
|
1514
1544
|
}
|
|
1515
1545
|
}
|
|
@@ -1544,6 +1574,14 @@ function createProjectContext(opts) {
|
|
|
1544
1574
|
}
|
|
1545
1575
|
}
|
|
1546
1576
|
}
|
|
1577
|
+
if (boundSession && serverName === "clay-handoff") {
|
|
1578
|
+
var handoffTools = _sessionHandoff.getToolDefs(boundSession);
|
|
1579
|
+
for (var hti = 0; hti < handoffTools.length; hti++) {
|
|
1580
|
+
if (handoffTools[hti].name === toolName && typeof handoffTools[hti].handler === "function") {
|
|
1581
|
+
return Promise.resolve(handoffTools[hti].handler(args || {}));
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1547
1585
|
if (boundSession && serverName === "clay-documents") {
|
|
1548
1586
|
var documentTools = _sessionDocument.getToolDefs(boundSession);
|
|
1549
1587
|
for (var dti = 0; dti < documentTools.length; dti++) {
|
|
@@ -1552,7 +1590,7 @@ function createProjectContext(opts) {
|
|
|
1552
1590
|
}
|
|
1553
1591
|
}
|
|
1554
1592
|
}
|
|
1555
|
-
if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-documents") {
|
|
1593
|
+
if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents") {
|
|
1556
1594
|
return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
|
|
1557
1595
|
}
|
|
1558
1596
|
if (sessionOnly) return Promise.reject(new Error("Session tool not found: " + serverName + "/" + toolName));
|
|
@@ -97,6 +97,9 @@ function buildHandoffContext(options) {
|
|
|
97
97
|
if (latestUser) parts.push("Current user request, verbatim:\n" + latestUser);
|
|
98
98
|
parts.push("Repository state at handoff:\n" + repositoryState(options.cwd));
|
|
99
99
|
parts.push("Recent conversation:\n" + transcriptText(turns));
|
|
100
|
+
if (options.sourceReadTool) {
|
|
101
|
+
parts.push("The snapshot above is partial. The read_handoff_source tool from the clay-handoff MCP server can read the full original session, including summarized tool calls and older turns. Call it when the snapshot leaves a question open.");
|
|
102
|
+
}
|
|
100
103
|
parts.push("Continue from the unresolved work above. Preserve the user's decisions and constraints, inspect the actual files before making assumptions, and proceed without asking the user to repeat context.");
|
|
101
104
|
return trimText(parts.join("\n\n"), MAX_CONTEXT_CHARS);
|
|
102
105
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Session-bound access to the source of a Clay session handoff.
|
|
2
|
+
|
|
3
|
+
var buildShape = require("./session-spawn-mcp-server").buildShape;
|
|
4
|
+
|
|
5
|
+
var TOOL_DESCRIPTION =
|
|
6
|
+
"This session was continued from another agent's session via a context snapshot. " +
|
|
7
|
+
"That snapshot omitted tool calls and older turns. Read the original Clay session record directly, including user messages, assistant text, and summarized tool calls, regardless of which vendor produced it.";
|
|
8
|
+
|
|
9
|
+
function getToolDefs(handlers) {
|
|
10
|
+
return [
|
|
11
|
+
{
|
|
12
|
+
name: "read_handoff_source",
|
|
13
|
+
description: TOOL_DESCRIPTION,
|
|
14
|
+
inputSchema: buildShape({
|
|
15
|
+
offset: {
|
|
16
|
+
type: "number",
|
|
17
|
+
description: "Skip the first N history entries. Omit to return the last limit entries.",
|
|
18
|
+
},
|
|
19
|
+
limit: {
|
|
20
|
+
type: "number",
|
|
21
|
+
description: "Maximum history entries to return. Defaults to 30 and is capped at 100.",
|
|
22
|
+
},
|
|
23
|
+
sourceSessionId: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Source session in this session's handoff chain. Omit to read the immediate source.",
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
handler: function (args) { return handlers.read(args || {}); },
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
TOOL_DESCRIPTION: TOOL_DESCRIPTION,
|
|
35
|
+
getToolDefs: getToolDefs,
|
|
36
|
+
};
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// codex "xhigh").
|
|
8
8
|
var EFFORT_ORDER = ["minimal", "low", "medium", "high", "xhigh", "max"];
|
|
9
9
|
|
|
10
|
+
// sessionBoundTools gates whether per-session MCP tool mounting reaches a vendor's process.
|
|
10
11
|
var VENDOR_REGISTRY = {
|
|
11
12
|
claude: {
|
|
12
13
|
displayName: "Claude Code",
|
|
@@ -16,6 +17,7 @@ var VENDOR_REGISTRY = {
|
|
|
16
17
|
sessionModes: ["gui", "tui"],
|
|
17
18
|
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
18
19
|
osUserIsolation: true,
|
|
20
|
+
sessionBoundTools: true,
|
|
19
21
|
usageDashboard: {
|
|
20
22
|
icon: "/claude-code-avatar.png",
|
|
21
23
|
alt: "Claude Code",
|
|
@@ -32,6 +34,7 @@ var VENDOR_REGISTRY = {
|
|
|
32
34
|
sessionModes: ["gui"],
|
|
33
35
|
effortLevels: ["minimal", "low", "medium", "high", "xhigh"],
|
|
34
36
|
osUserIsolation: true,
|
|
37
|
+
sessionBoundTools: false,
|
|
35
38
|
usageDashboard: {
|
|
36
39
|
icon: "/codex-avatar.png",
|
|
37
40
|
alt: "Codex",
|
|
@@ -48,6 +51,7 @@ var VENDOR_REGISTRY = {
|
|
|
48
51
|
sessionModes: ["gui"],
|
|
49
52
|
effortLevels: ["low", "medium", "high"],
|
|
50
53
|
osUserIsolation: false,
|
|
54
|
+
sessionBoundTools: false,
|
|
51
55
|
usageDashboard: null,
|
|
52
56
|
rateLimitTracking: false,
|
|
53
57
|
},
|
|
@@ -59,6 +63,7 @@ var VENDOR_REGISTRY = {
|
|
|
59
63
|
sessionModes: ["gui"],
|
|
60
64
|
effortLevels: [],
|
|
61
65
|
osUserIsolation: false,
|
|
66
|
+
sessionBoundTools: true,
|
|
62
67
|
usageDashboard: null,
|
|
63
68
|
rateLimitTracking: false,
|
|
64
69
|
},
|
|
@@ -70,6 +75,7 @@ var VENDOR_REGISTRY = {
|
|
|
70
75
|
sessionModes: ["gui"],
|
|
71
76
|
effortLevels: [],
|
|
72
77
|
osUserIsolation: false,
|
|
78
|
+
sessionBoundTools: true,
|
|
73
79
|
usageDashboard: null,
|
|
74
80
|
rateLimitTracking: false,
|
|
75
81
|
},
|
|
@@ -81,6 +87,7 @@ var VENDOR_REGISTRY = {
|
|
|
81
87
|
sessionModes: ["gui"],
|
|
82
88
|
effortLevels: [],
|
|
83
89
|
osUserIsolation: false,
|
|
90
|
+
sessionBoundTools: true,
|
|
84
91
|
usageDashboard: null,
|
|
85
92
|
rateLimitTracking: false,
|
|
86
93
|
},
|
|
@@ -92,6 +99,7 @@ var VENDOR_REGISTRY = {
|
|
|
92
99
|
sessionModes: ["gui"],
|
|
93
100
|
effortLevels: [],
|
|
94
101
|
osUserIsolation: false,
|
|
102
|
+
sessionBoundTools: true,
|
|
95
103
|
usageDashboard: null,
|
|
96
104
|
rateLimitTracking: false,
|
|
97
105
|
},
|
|
@@ -103,6 +111,7 @@ var VENDOR_REGISTRY = {
|
|
|
103
111
|
sessionModes: ["gui"],
|
|
104
112
|
effortLevels: [],
|
|
105
113
|
osUserIsolation: false,
|
|
114
|
+
sessionBoundTools: true,
|
|
106
115
|
usageDashboard: null,
|
|
107
116
|
rateLimitTracking: false,
|
|
108
117
|
},
|
|
@@ -114,6 +123,7 @@ var VENDOR_REGISTRY = {
|
|
|
114
123
|
sessionModes: ["gui"],
|
|
115
124
|
effortLevels: [],
|
|
116
125
|
osUserIsolation: false,
|
|
126
|
+
sessionBoundTools: true,
|
|
117
127
|
usageDashboard: null,
|
|
118
128
|
rateLimitTracking: false,
|
|
119
129
|
},
|
|
@@ -125,6 +135,7 @@ var VENDOR_REGISTRY = {
|
|
|
125
135
|
sessionModes: ["gui"],
|
|
126
136
|
effortLevels: [],
|
|
127
137
|
osUserIsolation: false,
|
|
138
|
+
sessionBoundTools: true,
|
|
128
139
|
usageDashboard: null,
|
|
129
140
|
rateLimitTracking: false,
|
|
130
141
|
},
|
package/package.json
CHANGED