clay-server 3.8.1 → 4.0.0-beta.10
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/lib/ask-user-mcp-server.js +5 -119
- package/lib/background-task-timing.js +105 -0
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +23 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +224 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +17 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +23 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-mcp-server.js +290 -0
- package/lib/project-logs-query.js +167 -0
- package/lib/project-logs-root.js +67 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +357 -0
- package/lib/project-logs-snapshot.js +202 -0
- package/lib/project-logs-store.js +498 -0
- package/lib/project-logs-versioning.js +128 -0
- package/lib/project-logs.js +347 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +36 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +414 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +433 -102
- package/lib/public/app.js +109 -48
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/input.css +79 -25
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/project-logs.css +234 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +96 -74
- package/lib/public/modules/app-connection.js +100 -5
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +124 -38
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-panels.js +43 -2
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/background-tasks-ui.js +139 -16
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +165 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-logs-ambient.js +238 -0
- package/lib/public/modules/project-logs-render.js +359 -0
- package/lib/public/modules/project-logs.js +328 -0
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +12 -73
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/sidebar-sessions.js +25 -1
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +106 -53
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-palette.js +76 -4
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +14 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +34 -13
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +166 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +22 -4
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +107 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +141 -46
- package/lib/yoke/adapters/codex.js +79 -11
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-background-tasks.js +8 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +4 -3
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Session-bound `clay-knowledge` wiring for Mate projects.
|
|
2
|
+
//
|
|
3
|
+
// Mate Knowledge is available only inside a Mate project. A non-Mate Project
|
|
4
|
+
// Driver session gets nothing here and continues to use `clay-logs`. Which
|
|
5
|
+
// tool set a Mate receives is decided by the server Mate registry through the
|
|
6
|
+
// service binder, never by a project flag or a tool argument.
|
|
7
|
+
|
|
8
|
+
var knowledgeMcp = require("./mate-knowledge-mcp-server");
|
|
9
|
+
|
|
10
|
+
var SYSTEM_PROMPT_LABEL = "--- Your Knowledge (durable personal and expertise context; manage via clay-knowledge tools) ---";
|
|
11
|
+
var CLAY_PROMPT_LABEL = "--- Mate Knowledge coordination (via clay-knowledge tools) ---";
|
|
12
|
+
|
|
13
|
+
function attachProjectMateKnowledge(ctx) {
|
|
14
|
+
var service = ctx.service;
|
|
15
|
+
var sm = ctx.sm;
|
|
16
|
+
var slug = ctx.projectSlug;
|
|
17
|
+
var isMate = ctx.isMate === true;
|
|
18
|
+
var mateId = ctx.mateId || null;
|
|
19
|
+
var getProjectOwnerId = ctx.getProjectOwnerId || function () { return null; };
|
|
20
|
+
|
|
21
|
+
function binding(session) {
|
|
22
|
+
if (!service || !isMate || !mateId) return null;
|
|
23
|
+
if (session && (!sm || !sm.sessions || sm.sessions.get(session.localId) !== session)) return null;
|
|
24
|
+
return service.bind({
|
|
25
|
+
projectSlug: slug,
|
|
26
|
+
projectOwnerId: getProjectOwnerId(),
|
|
27
|
+
isMate: true,
|
|
28
|
+
mateId: mateId,
|
|
29
|
+
session: session || null,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Decided once from the project-level binding so a static descriptor and a
|
|
34
|
+
// session-bound server always advertise the same tool set.
|
|
35
|
+
function includeClay() {
|
|
36
|
+
var projectBound = binding(null);
|
|
37
|
+
return !!(projectBound && projectBound.isClay === true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getToolDefs(session) {
|
|
41
|
+
if (!service || !isMate) return [];
|
|
42
|
+
var bound = session ? binding(session) : null;
|
|
43
|
+
if (session && !bound) return [];
|
|
44
|
+
return knowledgeMcp.getToolDefs(bound, includeClay());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createMcpServer(adapter, session) {
|
|
48
|
+
if (!service || !isMate) return null;
|
|
49
|
+
if (!binding(null)) return null;
|
|
50
|
+
var bound = session ? binding(session) : null;
|
|
51
|
+
// A session that cannot bind still gets the fail-closed descriptor rather
|
|
52
|
+
// than a silently missing server.
|
|
53
|
+
return knowledgeMcp.createMcpServer(adapter, bound, includeClay());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getDynamicToolDefs(session) {
|
|
57
|
+
return getToolDefs(session).map(function (tool) {
|
|
58
|
+
tool.permissionName = "mcp__clay-knowledge__" + tool.name;
|
|
59
|
+
return tool;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getBridgeTools(session, normalizeSchema) {
|
|
64
|
+
if (!session) return [];
|
|
65
|
+
var defs = getToolDefs(session);
|
|
66
|
+
var tools = [];
|
|
67
|
+
for (var i = 0; i < defs.length; i++) {
|
|
68
|
+
tools.push({
|
|
69
|
+
server: "clay-knowledge",
|
|
70
|
+
name: defs[i].name,
|
|
71
|
+
description: defs[i].description || defs[i].name,
|
|
72
|
+
inputSchema: normalizeSchema(defs[i].inputSchema),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return tools;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function callBridgeTool(session, toolName, args) {
|
|
79
|
+
if (!session) return Promise.reject(new Error("Knowledge tools require a valid Mate session."));
|
|
80
|
+
var defs = getToolDefs(session);
|
|
81
|
+
for (var i = 0; i < defs.length; i++) {
|
|
82
|
+
if (defs[i].name === toolName) return Promise.resolve(defs[i].handler(args || {}));
|
|
83
|
+
}
|
|
84
|
+
return Promise.reject(new Error("Knowledge tool not found: " + toolName));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getSystemPrompt(session) {
|
|
88
|
+
if (!service || !isMate) return "";
|
|
89
|
+
var bound = session ? binding(session) : binding(null);
|
|
90
|
+
if (!bound) return "";
|
|
91
|
+
return bound.isClay
|
|
92
|
+
? CLAY_PROMPT_LABEL + "\n" + knowledgeMcp.CLAY_CONTRACT
|
|
93
|
+
: SYSTEM_PROMPT_LABEL + "\n" + knowledgeMcp.MATE_CONTRACT;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
createMcpServer: createMcpServer,
|
|
98
|
+
getToolDefs: getToolDefs,
|
|
99
|
+
getDynamicToolDefs: getDynamicToolDefs,
|
|
100
|
+
getBridgeTools: getBridgeTools,
|
|
101
|
+
callBridgeTool: callBridgeTool,
|
|
102
|
+
getSystemPrompt: getSystemPrompt,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
SYSTEM_PROMPT_LABEL: SYSTEM_PROMPT_LABEL,
|
|
108
|
+
CLAY_PROMPT_LABEL: CLAY_PROMPT_LABEL,
|
|
109
|
+
attachProjectMateKnowledge: attachProjectMateKnowledge,
|
|
110
|
+
};
|
package/lib/project-memory.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
var fs = require("fs");
|
|
2
2
|
var path = require("path");
|
|
3
|
+
var mateSync = require("./mate-knowledge-sync");
|
|
4
|
+
|
|
5
|
+
// Mirror a Mate-owned durable memory source into the Clay-wide Knowledge
|
|
6
|
+
// backend after the legacy write has already succeeded. Reconciling the source
|
|
7
|
+
// covers writes, rewrites, and removals with one call.
|
|
8
|
+
function mirrorMateSource(mateDir, fileName, actor) {
|
|
9
|
+
mateSync.syncQuietly({
|
|
10
|
+
mateDir: mateDir,
|
|
11
|
+
fileName: fileName,
|
|
12
|
+
actor: actor || { type: "agent" },
|
|
13
|
+
});
|
|
14
|
+
}
|
|
3
15
|
|
|
4
16
|
function attachMemory(ctx) {
|
|
5
17
|
var cwd = ctx.cwd;
|
|
@@ -8,7 +20,8 @@ function attachMemory(ctx) {
|
|
|
8
20
|
var sendTo = ctx.sendTo;
|
|
9
21
|
var matesModule = ctx.matesModule;
|
|
10
22
|
var sessionSearch = ctx.sessionSearch;
|
|
11
|
-
var
|
|
23
|
+
var getWorkspaceMemorySessions = ctx.getWorkspaceMemorySessions || function () { return []; };
|
|
24
|
+
var getOwnedCurrentSessions = ctx.getOwnedCurrentSessions || function () { return []; };
|
|
12
25
|
var projectOwnerId = ctx.projectOwnerId;
|
|
13
26
|
var handleMessage = ctx.handleMessage;
|
|
14
27
|
|
|
@@ -166,7 +179,7 @@ function attachMemory(ctx) {
|
|
|
166
179
|
var timelineEntries = [];
|
|
167
180
|
|
|
168
181
|
// Own sessions
|
|
169
|
-
|
|
182
|
+
getOwnedCurrentSessions().forEach(function (s) {
|
|
170
183
|
if (s.hidden || !s.history || s.history.length === 0) return;
|
|
171
184
|
timelineEntries.push({
|
|
172
185
|
title: s.title || "New Session",
|
|
@@ -176,7 +189,7 @@ function attachMemory(ctx) {
|
|
|
176
189
|
});
|
|
177
190
|
|
|
178
191
|
// Cross-project sessions
|
|
179
|
-
var crossForTimeline =
|
|
192
|
+
var crossForTimeline = getWorkspaceMemorySessions();
|
|
180
193
|
for (var cti = 0; cti < crossForTimeline.length; cti++) {
|
|
181
194
|
var cs = crossForTimeline[cti];
|
|
182
195
|
timelineEntries.push({
|
|
@@ -209,7 +222,7 @@ function attachMemory(ctx) {
|
|
|
209
222
|
try {
|
|
210
223
|
// Collect mate's own sessions
|
|
211
224
|
var mateSessions = [];
|
|
212
|
-
|
|
225
|
+
getOwnedCurrentSessions().forEach(function (s) {
|
|
213
226
|
if (!s.hidden && s.history && s.history.length > 0) {
|
|
214
227
|
mateSessions.push(s);
|
|
215
228
|
}
|
|
@@ -218,7 +231,7 @@ function attachMemory(ctx) {
|
|
|
218
231
|
// globalSearch: also collect sessions from all other projects + knowledge files
|
|
219
232
|
var knowledgeFiles = [];
|
|
220
233
|
if (hasGlobalSearch) {
|
|
221
|
-
var crossSessions =
|
|
234
|
+
var crossSessions = getWorkspaceMemorySessions();
|
|
222
235
|
for (var cs = 0; cs < crossSessions.length; cs++) {
|
|
223
236
|
mateSessions.push(crossSessions[cs]);
|
|
224
237
|
}
|
|
@@ -466,6 +479,7 @@ function attachMemory(ctx) {
|
|
|
466
479
|
}
|
|
467
480
|
fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
468
481
|
fs.writeFileSync(summaryFile, cleaned + "\n", "utf8");
|
|
482
|
+
mirrorMateSource(path.dirname(knowledgeDir), "memory-summary.md");
|
|
469
483
|
console.log("[memory-summary] Updated memory-summary.md for mate " + mateId);
|
|
470
484
|
} catch (e) {
|
|
471
485
|
console.error("[memory-summary] Failed to write memory-summary.md for mate " + mateId + ":", e.message);
|
|
@@ -572,6 +586,7 @@ function attachMemory(ctx) {
|
|
|
572
586
|
}
|
|
573
587
|
fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
574
588
|
fs.writeFileSync(summaryFile, cleaned + "\n", "utf8");
|
|
589
|
+
mirrorMateSource(path.dirname(knowledgeDir), "memory-summary.md");
|
|
575
590
|
console.log("[memory-summary] Generated initial memory-summary.md for mate " + mateId + " from " + digestsText.length + " digests");
|
|
576
591
|
} catch (e) {
|
|
577
592
|
console.error("[memory-summary] Failed to write initial memory-summary.md for mate " + mateId + ":", e.message);
|
|
@@ -595,7 +610,7 @@ function attachMemory(ctx) {
|
|
|
595
610
|
|
|
596
611
|
// --- Message handlers for memory management UI ---
|
|
597
612
|
|
|
598
|
-
function
|
|
613
|
+
function readMemoryState() {
|
|
599
614
|
var digestFile = path.join(cwd, "knowledge", "session-digests.jsonl");
|
|
600
615
|
var summaryFile = path.join(cwd, "knowledge", "memory-summary.md");
|
|
601
616
|
var entries = [];
|
|
@@ -620,7 +635,12 @@ function attachMemory(ctx) {
|
|
|
620
635
|
} catch (e) {}
|
|
621
636
|
// Return newest first
|
|
622
637
|
entries.reverse();
|
|
623
|
-
|
|
638
|
+
return { entries: entries, summary: summary };
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function handleMemoryList(ws) {
|
|
642
|
+
var state = readMemoryState();
|
|
643
|
+
sendTo(ws, { type: "memory_list", entries: state.entries, summary: state.summary });
|
|
624
644
|
}
|
|
625
645
|
|
|
626
646
|
function handleMemorySearch(ws, msg) {
|
|
@@ -660,6 +680,14 @@ function attachMemory(ctx) {
|
|
|
660
680
|
} else {
|
|
661
681
|
fs.writeFileSync(digestFile, lines.join("\n") + "\n");
|
|
662
682
|
}
|
|
683
|
+
// Reconciling the journal after the rewrite tombstones the removed
|
|
684
|
+
// line, so a deleted memory does not stay active in the new backend.
|
|
685
|
+
var deleteUser = (ws && ws._clayUser) || null;
|
|
686
|
+
mirrorMateSource(cwd, "session-digests.jsonl", {
|
|
687
|
+
type: deleteUser ? "user" : "system",
|
|
688
|
+
userId: deleteUser ? deleteUser.id : null,
|
|
689
|
+
displayName: deleteUser ? (deleteUser.displayName || deleteUser.username) : null,
|
|
690
|
+
});
|
|
663
691
|
}
|
|
664
692
|
} catch (e) {}
|
|
665
693
|
sendTo(ws, { type: "memory_deleted", index: msg.index });
|
|
@@ -671,6 +699,7 @@ function attachMemory(ctx) {
|
|
|
671
699
|
gateMemory: gateMemory,
|
|
672
700
|
updateMemorySummary: updateMemorySummary,
|
|
673
701
|
initMemorySummary: initMemorySummary,
|
|
702
|
+
readMemoryState: readMemoryState,
|
|
674
703
|
handleMemoryList: handleMemoryList,
|
|
675
704
|
handleMemorySearch: handleMemorySearch,
|
|
676
705
|
handleMemoryDelete: handleMemoryDelete,
|
package/lib/project-models.js
CHANGED
|
@@ -12,6 +12,46 @@ function modelEntryMatches(entry, value) {
|
|
|
12
12
|
return entry.value === value || entry.id === value || entry.resolvedModel === value;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function normalizeCatalogModels(models) {
|
|
16
|
+
var normalized = [];
|
|
17
|
+
models = models || [];
|
|
18
|
+
for (var i = 0; i < models.length; i++) {
|
|
19
|
+
var value = modelEntryValue(models[i]);
|
|
20
|
+
if (!value) continue;
|
|
21
|
+
var displayName = typeof models[i] === "string" ? models[i] : (models[i].displayName || models[i].name || value);
|
|
22
|
+
var searchParts = [value, displayName];
|
|
23
|
+
if (typeof models[i] === "object") {
|
|
24
|
+
searchParts.push(models[i].id || "");
|
|
25
|
+
searchParts.push(models[i].resolvedModel || "");
|
|
26
|
+
}
|
|
27
|
+
normalized.push({ value: value, displayName: displayName, search: searchParts.join(" ").toLowerCase(), source: models[i] });
|
|
28
|
+
}
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function selectCatalogModel(models, defaultModel, alias) {
|
|
33
|
+
var entries = normalizeCatalogModels(models);
|
|
34
|
+
if (entries.length === 0) return null;
|
|
35
|
+
var configured = null;
|
|
36
|
+
for (var i = 0; i < entries.length; i++) {
|
|
37
|
+
if (modelEntryMatches(entries[i].source, defaultModel)) {
|
|
38
|
+
configured = entries[i];
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
alias = alias === "fast" || alias === "deep" ? alias : "standard";
|
|
43
|
+
if (alias === "standard" && configured) return configured;
|
|
44
|
+
var matcher = alias === "fast"
|
|
45
|
+
? /haiku|mini|flash|fast|lite|small|luna/
|
|
46
|
+
: alias === "deep"
|
|
47
|
+
? /opus|\bpro\b|max|deep|large|\bsol\b|reason/
|
|
48
|
+
: /sonnet|standard|balanced|terra/;
|
|
49
|
+
for (var mi = 0; mi < entries.length; mi++) {
|
|
50
|
+
if (matcher.test(entries[mi].search)) return entries[mi];
|
|
51
|
+
}
|
|
52
|
+
return configured || entries[0];
|
|
53
|
+
}
|
|
54
|
+
|
|
15
55
|
function attachModels(ctx) {
|
|
16
56
|
var cwd = ctx.cwd;
|
|
17
57
|
var slug = ctx.slug;
|
|
@@ -25,26 +65,36 @@ function attachModels(ctx) {
|
|
|
25
65
|
var serverTls = ctx.serverTls;
|
|
26
66
|
var serverAuthToken = ctx.serverAuthToken;
|
|
27
67
|
|
|
28
|
-
|
|
29
|
-
var
|
|
30
|
-
var
|
|
31
|
-
var
|
|
32
|
-
var
|
|
33
|
-
|
|
68
|
+
function getVendorAvailability() {
|
|
69
|
+
var available = (sm.availableVendors || []).slice();
|
|
70
|
+
var installed = (sm.installedVendors || []).slice();
|
|
71
|
+
var ids = available.slice();
|
|
72
|
+
for (var i = 0; i < installed.length; i++) {
|
|
73
|
+
if (ids.indexOf(installed[i]) === -1) ids.push(installed[i]);
|
|
74
|
+
}
|
|
75
|
+
return ids.map(function (vendor) {
|
|
76
|
+
var info = yoke.getVendorInfo(vendor);
|
|
77
|
+
return {
|
|
78
|
+
id: vendor,
|
|
79
|
+
displayName: info && info.displayName ? info.displayName : vendor,
|
|
80
|
+
installed: installed.indexOf(vendor) !== -1,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
34
84
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
requestId: requestId,
|
|
40
|
-
modelStatus: "error",
|
|
41
|
-
error: "No vendor was selected.",
|
|
42
|
-
model: "",
|
|
43
|
-
models: [],
|
|
44
|
-
sessionId: session ? session.localId : null,
|
|
45
|
-
});
|
|
46
|
-
return;
|
|
85
|
+
function modelDisplayName(models, value) {
|
|
86
|
+
for (var i = 0; i < models.length; i++) {
|
|
87
|
+
if (!modelEntryMatches(models[i], value)) continue;
|
|
88
|
+
return typeof models[i] === "string" ? models[i] : (models[i].displayName || modelEntryValue(models[i]));
|
|
47
89
|
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function getVendorCatalog(ws, vendor) {
|
|
94
|
+
var loadError = null;
|
|
95
|
+
var loadedDefaultModel = "";
|
|
96
|
+
var vendorAdapter = null;
|
|
97
|
+
if (!vendor) return { vendor: "", models: [], capabilities: {}, status: "error", error: "No vendor was selected." };
|
|
48
98
|
|
|
49
99
|
try {
|
|
50
100
|
var modelLinuxUser = getLinuxUserForWs(ws);
|
|
@@ -75,6 +125,7 @@ function attachModels(ctx) {
|
|
|
75
125
|
});
|
|
76
126
|
sm.capabilitiesByVendor = sm.capabilitiesByVendor || {};
|
|
77
127
|
sm.capabilitiesByVendor[vendor] = readyResult.capabilities || {};
|
|
128
|
+
loadedDefaultModel = readyResult.defaultModel || "";
|
|
78
129
|
sm.modelsByVendor = sm.modelsByVendor || {};
|
|
79
130
|
if (Array.isArray(readyResult.models) && readyResult.models.length > 0) {
|
|
80
131
|
sm.modelsByVendor[vendor] = readyResult.models;
|
|
@@ -110,6 +161,84 @@ function attachModels(ctx) {
|
|
|
110
161
|
}
|
|
111
162
|
|
|
112
163
|
var vendorModels = (sm.modelsByVendor && sm.modelsByVendor[vendor]) || [];
|
|
164
|
+
var vendorInfo = yoke.getVendorInfo(vendor);
|
|
165
|
+
var displayName = vendorInfo ? vendorInfo.displayName : vendor;
|
|
166
|
+
var status = vendorModels.length > 0 ? "ready" : (loadError ? "error" : "empty");
|
|
167
|
+
var defaultModel = "";
|
|
168
|
+
var preferredModels = [
|
|
169
|
+
(sm.defaultModelByVendor && sm.defaultModelByVendor[vendor]) || "",
|
|
170
|
+
loadedDefaultModel,
|
|
171
|
+
];
|
|
172
|
+
for (var preferredIndex = 0; preferredIndex < preferredModels.length && !defaultModel; preferredIndex++) {
|
|
173
|
+
for (var modelIndex = 0; modelIndex < vendorModels.length; modelIndex++) {
|
|
174
|
+
if (!modelEntryMatches(vendorModels[modelIndex], preferredModels[preferredIndex])) continue;
|
|
175
|
+
defaultModel = modelEntryValue(vendorModels[modelIndex]);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
var errorText = "";
|
|
180
|
+
if (status === "error") {
|
|
181
|
+
errorText = "Could not load " + displayName + " models: " + (loadError.message || loadError);
|
|
182
|
+
} else if (status === "empty") {
|
|
183
|
+
errorText = displayName + " returned no models. Check CLI authentication and retry.";
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
vendor: vendor,
|
|
187
|
+
models: vendorModels,
|
|
188
|
+
defaultModel: defaultModel,
|
|
189
|
+
capabilities: (sm.capabilitiesByVendor && sm.capabilitiesByVendor[vendor]) || {},
|
|
190
|
+
availableVendors: sm.availableVendors || [],
|
|
191
|
+
installedVendors: sm.installedVendors || [],
|
|
192
|
+
status: status,
|
|
193
|
+
error: errorText,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function resolveConfiguredModel(ws, alias) {
|
|
198
|
+
var availability = getVendorAvailability();
|
|
199
|
+
var candidates = [];
|
|
200
|
+
var preferredVendor = sm.defaultVendor || "";
|
|
201
|
+
if (preferredVendor) candidates.push(preferredVendor);
|
|
202
|
+
for (var i = 0; i < availability.length; i++) {
|
|
203
|
+
if (candidates.indexOf(availability[i].id) === -1) candidates.push(availability[i].id);
|
|
204
|
+
}
|
|
205
|
+
var errors = [];
|
|
206
|
+
for (var ci = 0; ci < candidates.length; ci++) {
|
|
207
|
+
var catalog = await getVendorCatalog(ws, candidates[ci]);
|
|
208
|
+
var models = catalog.models || [];
|
|
209
|
+
var selected = selectCatalogModel(models, catalog.defaultModel, alias);
|
|
210
|
+
if (catalog.status !== "ready" || !selected) {
|
|
211
|
+
if (catalog.error) errors.push(catalog.error);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
var info = yoke.getVendorInfo(catalog.vendor);
|
|
215
|
+
return {
|
|
216
|
+
status: "ready",
|
|
217
|
+
vendor: catalog.vendor,
|
|
218
|
+
vendorName: info && info.displayName ? info.displayName : catalog.vendor,
|
|
219
|
+
alias: alias === "fast" || alias === "deep" ? alias : "standard",
|
|
220
|
+
model: selected.value,
|
|
221
|
+
modelName: selected.displayName || modelDisplayName(models, selected.value),
|
|
222
|
+
error: "",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
status: "error",
|
|
227
|
+
vendor: preferredVendor,
|
|
228
|
+
vendorName: preferredVendor ? ((yoke.getVendorInfo(preferredVendor) || {}).displayName || preferredVendor) : "",
|
|
229
|
+
model: "",
|
|
230
|
+
modelName: "",
|
|
231
|
+
alias: alias === "fast" || alias === "deep" ? alias : "standard",
|
|
232
|
+
error: errors[0] || "No configured model is available. Sign in to an installed model provider CLI, then retry.",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function loadVendorModels(ws, msg) {
|
|
237
|
+
var vendor = msg.vendor || "";
|
|
238
|
+
var requestId = msg.requestId || null;
|
|
239
|
+
var session = getSessionForWs(ws);
|
|
240
|
+
var catalog = await getVendorCatalog(ws, vendor);
|
|
241
|
+
var vendorModels = catalog.models;
|
|
113
242
|
var modelToSend = modelEntryValue(vendorModels[0]);
|
|
114
243
|
var preferredModel = (session && session.vendor === vendor && session.model) || (sm.defaultModelByVendor && sm.defaultModelByVendor[vendor]) || "";
|
|
115
244
|
if (preferredModel) {
|
|
@@ -120,27 +249,18 @@ function attachModels(ctx) {
|
|
|
120
249
|
}
|
|
121
250
|
}
|
|
122
251
|
}
|
|
123
|
-
var vendorInfo = yoke.getVendorInfo(vendor);
|
|
124
|
-
var displayName = vendorInfo ? vendorInfo.displayName : vendor;
|
|
125
|
-
var status = vendorModels.length > 0 ? "ready" : (loadError ? "error" : "empty");
|
|
126
|
-
var errorText = "";
|
|
127
|
-
if (status === "error") {
|
|
128
|
-
errorText = "Could not load " + displayName + " models: " + (loadError.message || loadError);
|
|
129
|
-
} else if (status === "empty") {
|
|
130
|
-
errorText = displayName + " returned no models. Check CLI authentication and retry.";
|
|
131
|
-
}
|
|
132
252
|
sendTo(ws, {
|
|
133
253
|
type: "model_info",
|
|
134
254
|
model: modelToSend,
|
|
135
255
|
models: vendorModels,
|
|
136
256
|
vendor: vendor,
|
|
137
257
|
sessionId: session ? session.localId : null,
|
|
138
|
-
capabilities:
|
|
139
|
-
availableVendors:
|
|
140
|
-
installedVendors:
|
|
258
|
+
capabilities: catalog.capabilities,
|
|
259
|
+
availableVendors: catalog.availableVendors,
|
|
260
|
+
installedVendors: catalog.installedVendors,
|
|
141
261
|
requestId: requestId,
|
|
142
|
-
modelStatus: status,
|
|
143
|
-
error:
|
|
262
|
+
modelStatus: catalog.status,
|
|
263
|
+
error: catalog.error,
|
|
144
264
|
});
|
|
145
265
|
}
|
|
146
266
|
|
|
@@ -208,6 +328,9 @@ function attachModels(ctx) {
|
|
|
208
328
|
|
|
209
329
|
return {
|
|
210
330
|
handleMessage: handleMessage,
|
|
331
|
+
getVendorCatalog: getVendorCatalog,
|
|
332
|
+
getVendorAvailability: getVendorAvailability,
|
|
333
|
+
resolveConfiguredModel: resolveConfiguredModel,
|
|
211
334
|
loadVendorModels: loadVendorModels,
|
|
212
335
|
selectModel: selectModel,
|
|
213
336
|
};
|
|
@@ -217,4 +340,6 @@ module.exports = {
|
|
|
217
340
|
attachModels: attachModels,
|
|
218
341
|
modelEntryMatches: modelEntryMatches,
|
|
219
342
|
modelEntryValue: modelEntryValue,
|
|
343
|
+
normalizeCatalogModels: normalizeCatalogModels,
|
|
344
|
+
selectCatalogModel: selectCatalogModel,
|
|
220
345
|
};
|
|
@@ -7,7 +7,7 @@ var MAX_NOTE_PROMPT_CHARS = 800;
|
|
|
7
7
|
var NOTES_LABEL = "--- Project sticky notes (cross-session work memory; manage via clay-notes tools) ---";
|
|
8
8
|
var NOTES_HINT = "- More notes are available; call list_notes for the rest.";
|
|
9
9
|
var PROACTIVE_POLICY = sessionNotesMcp.MEMORY_CONTRACT + " If an injected preview is relevant or truncated, call list_notes before acting or writing so you do not create a duplicate.";
|
|
10
|
-
var NOTE_COLORS = ["
|
|
10
|
+
var NOTE_COLORS = ["purple", "green", "yellow", "blue", "pink", "orange"];
|
|
11
11
|
|
|
12
12
|
function toolResult(value) {
|
|
13
13
|
return Promise.resolve({ content: [{ type: "text", text: JSON.stringify(value) }] });
|
|
@@ -150,7 +150,7 @@ function attachSessionNotes(ctx) {
|
|
|
150
150
|
var placement = autoPlacement(notes);
|
|
151
151
|
var created = nm.create({
|
|
152
152
|
text: text,
|
|
153
|
-
color: color || "
|
|
153
|
+
color: color || "purple",
|
|
154
154
|
x: placement.x,
|
|
155
155
|
y: placement.y,
|
|
156
156
|
origin: { sessionId: caller.localId, vendor: caller.vendor || "claude" },
|
|
@@ -100,11 +100,11 @@ function attachSessionPair(ctx) {
|
|
|
100
100
|
var response = token.response || "";
|
|
101
101
|
var text;
|
|
102
102
|
if (token.interrupted) {
|
|
103
|
-
text = "[Worker execution interrupted] The user interrupted the Worker mid-turn. Its work is PARTIAL and unverified — do not treat it as finished. Review what was done and decide next steps with the user.";
|
|
103
|
+
text = "[Split Worker execution interrupted] The user interrupted the Split Worker mid-turn. Its work is PARTIAL and unverified — do not treat it as finished. Review what was done and decide next steps with the user.";
|
|
104
104
|
} else {
|
|
105
|
-
text = "A Worker task delegated through send_to_partner has finished.\n\n" +
|
|
105
|
+
text = "A Split Worker task delegated through send_to_partner has finished.\n\n" +
|
|
106
106
|
"Original task:\n" + token.message + "\n\n" +
|
|
107
|
-
(failure ? "Worker error:\n" + failure : "Worker result:\n" + (response || "(No text response was recorded.)")) +
|
|
107
|
+
(failure ? "Split Worker error:\n" + failure : "Split Worker result:\n" + (response || "(No text response was recorded.)")) +
|
|
108
108
|
"\n\nReview the result, verify it as needed, and continue the task.";
|
|
109
109
|
}
|
|
110
110
|
sm.sendAndRecord(caller, {
|
|
@@ -361,7 +361,7 @@ function attachSessionPair(ctx) {
|
|
|
361
361
|
var driver;
|
|
362
362
|
var groupName;
|
|
363
363
|
if (Number.isInteger(driverSpec.sessionId)) {
|
|
364
|
-
// "Add Worker" on an existing session: the current session becomes
|
|
364
|
+
// "Add Split Worker" on an existing session: the current session becomes
|
|
365
365
|
// the Driver with its full conversation context intact.
|
|
366
366
|
driver = sm.sessions.get(driverSpec.sessionId);
|
|
367
367
|
if (!driver) throw new Error("driver session not found");
|
|
@@ -378,7 +378,7 @@ function attachSessionPair(ctx) {
|
|
|
378
378
|
}
|
|
379
379
|
var workerEffort = yoke.clampEffort(workerVendor, workerSpec.effort || (sm.currentEffortByVendor && sm.currentEffortByVendor[workerVendor]) || sm.currentEffort || "medium") || null;
|
|
380
380
|
var worker = sm.createSessionRaw({ ownerId: ownerId, vendor: workerVendor, model: workerSpec.model || null, effort: workerEffort });
|
|
381
|
-
worker.title = "Worker · " + ((yoke.getVendorInfo(workerVendor) || {}).displayName || workerVendor);
|
|
381
|
+
worker.title = "Split Worker · " + ((yoke.getVendorInfo(workerVendor) || {}).displayName || workerVendor);
|
|
382
382
|
if (workerSpec.effort) worker.loopSettings = { effort: workerSpec.effort };
|
|
383
383
|
var result = store.create(ws, {
|
|
384
384
|
members: [driver.localId, worker.localId],
|
|
@@ -393,7 +393,7 @@ function attachSessionPair(ctx) {
|
|
|
393
393
|
function createWorkerForDriver(driver, args) {
|
|
394
394
|
if (ctx.isMate) throw new Error("Pair sessions are only available in projects");
|
|
395
395
|
var installed = sm.installedVendors || [];
|
|
396
|
-
if (installed.length === 0) throw new Error("no coding agent is installed for a Worker session");
|
|
396
|
+
if (installed.length === 0) throw new Error("no coding agent is installed for a Split Worker session");
|
|
397
397
|
var vendor = typeof args.workerVendor === "string" ? args.workerVendor.trim() : "";
|
|
398
398
|
if (vendor) validateVendor(vendor);
|
|
399
399
|
if (!vendor) {
|
|
@@ -468,9 +468,9 @@ function attachSessionPair(ctx) {
|
|
|
468
468
|
var group = store.groupForMember(session.localId);
|
|
469
469
|
var pairPrompt = "";
|
|
470
470
|
if (group && group.pair && group.pair.driverId === session.localId) {
|
|
471
|
-
pairPrompt = "You are the Driver in a two-agent pair. The tools send_to_partner, read_partner, interrupt_partner, and close_partner are provided directly to you. Use send_to_partner to delegate concrete bounded work to the Worker. The human may also message or stop the Worker directly; treat that intervention as authoritative. Use close_partner immediately when the human asks to close, dismiss, or remove the Worker pane; it preserves the session history. A completed Worker turn leaves the Worker session available for more work. Use interrupt_partner when execution must stop or change direction but the pair should remain open; its work is partial and unverified until you review it. If review or user feedback requires corrections to the Worker's implementation, delegate a follow-up turn to that Worker instead of editing the Worker-owned files yourself. If the Worker is no longer available, keep the work in the visible Worker flow and use send_to_partner again after the stale pair is removed; never substitute a background
|
|
471
|
+
pairPrompt = "You are the Driver in a two-agent pair. The tools send_to_partner, read_partner, interrupt_partner, and close_partner are provided directly to you. Infer the user's intended target from conversational and UI context. References to the user-visible paired or split pane, its session, its activity or status, or a collaborator the user opened resolve to Clay's Split Worker and the appropriate partner tool. Internal Sub-agents are a distinct execution mechanism, not a lexical category; use them only when the user clearly intends internal or background parallel delegation rather than the visible paired session. When ambiguous and a visible pair exists, prefer the visible Split Worker. If the ambiguity would materially change where work runs, ask a concise clarification instead of guessing. Use send_to_partner to delegate concrete bounded work to the Split Worker. The human may also message or stop the Split Worker directly; treat that intervention as authoritative. Use close_partner immediately when the human asks to close, dismiss, or remove the Split Worker pane; it preserves the session history. A completed Split Worker turn leaves the Split Worker session available for more work. Use interrupt_partner when execution must stop or change direction but the pair should remain open; its work is partial and unverified until you review it. If review or user feedback requires corrections to the Split Worker's implementation, delegate a follow-up turn to that Split Worker instead of editing the Split Worker-owned files yourself. If the Split Worker is no longer available, keep the work in the visible Split Worker flow and use send_to_partner again after the stale pair is removed; never substitute a background Sub-agent. If a non-waiting delegation finishes later, Clay pushes the result back and resumes you automatically; use read_partner only when you need an interim status check. Integrate and verify the final outcome. Do not search the project for implementations of these tools, and do not delegate work that must be performed sequentially in this same session.";
|
|
472
472
|
} else if (!group && !ctx.isMate) {
|
|
473
|
-
pairPrompt = "
|
|
473
|
+
pairPrompt = "Infer the user's intended target from conversational and UI context. References to a user-visible paired or split pane, its session, its activity or status, or a collaborator the user wants opened resolve to Clay's Split Worker and its partner tools. Internal Sub-agents are a distinct execution mechanism, not a lexical category; use them only when the user clearly intends internal or background parallel delegation rather than a visible paired session. When ambiguity would materially change where work runs, ask a concise clarification instead of guessing. When the user intends a visible collaborator, call send_to_partner directly; Clay will create the paired Split Worker session and open it in the right pane automatically before delivering the task. Do not ask the user to start split mode and do not use a background Sub-agent as a substitute for a visible Split Worker.";
|
|
474
474
|
}
|
|
475
475
|
return [pairPrompt, workerProposal.getSystemPrompt(session)].filter(Boolean).join("\n\n");
|
|
476
476
|
}
|