clay-server 4.0.0-beta.9 → 4.0.0
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/capsule-display-floor.js +51 -0
- package/lib/capsule-frame-server.js +255 -0
- package/lib/capsule-mate-turn.js +105 -0
- package/lib/capsule-pig-logic.js +300 -0
- package/lib/capsule-server-runtimes.js +39 -0
- package/lib/capsules/pig/display.js +198 -0
- package/lib/capsules/pig/manifest.json +9 -0
- package/lib/capsules/pig/ui.json +84 -0
- package/lib/config.js +25 -1
- package/lib/daemon-projects.js +13 -8
- package/lib/daemon.js +127 -14
- package/lib/git-cli.js +95 -1
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +240 -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/migrate-single-user.js +2 -0
- package/lib/notes-lifecycle.js +149 -0
- package/lib/notes.js +60 -3
- package/lib/os-users.js +3 -1
- package/lib/project-capsule-catalog.js +9 -1
- package/lib/project-capsule-turn.js +96 -0
- package/lib/project-connection.js +15 -1
- package/lib/project-file-history.js +223 -0
- package/lib/project-file-watch.js +77 -49
- package/lib/project-filesystem.js +31 -220
- package/lib/project-http.js +15 -1
- package/lib/project-knowledge.js +22 -0
- package/lib/project-log-context.js +172 -0
- package/lib/project-log-feedback-delivery.js +118 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-context-state.js +42 -0
- package/lib/project-logs-mcp-server.js +328 -0
- package/lib/project-logs-query.js +185 -0
- package/lib/project-logs-root.js +75 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +463 -0
- package/lib/project-logs-snapshot.js +205 -0
- package/lib/project-logs-store.js +495 -0
- package/lib/project-logs-versioning.js +132 -0
- package/lib/project-logs.js +400 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +22 -0
- package/lib/project-message-delivery.js +70 -0
- package/lib/project-pair-lifecycle.js +460 -0
- package/lib/project-request-access.js +66 -0
- package/lib/project-session-handoff.js +1 -1
- package/lib/project-session-notes.js +64 -13
- package/lib/project-session-pair.js +159 -146
- package/lib/project-session-spawn.js +1 -1
- package/lib/project-sessions.js +58 -13
- package/lib/project-user-message.js +53 -4
- package/lib/project-worker-permission.js +430 -0
- package/lib/project-worker-proposal.js +208 -62
- package/lib/project.js +185 -6
- package/lib/public/app.js +63 -35
- package/lib/public/css/admin.css +2 -2
- package/lib/public/css/capsule-ui.css +38 -0
- package/lib/public/css/command-palette.css +19 -9
- package/lib/public/css/git-placard.css +154 -0
- package/lib/public/css/home-hub.css +4 -0
- package/lib/public/css/home-session-actions.css +66 -0
- package/lib/public/css/home-sidebar.css +66 -0
- package/lib/public/css/input.css +84 -3
- package/lib/public/css/messages.css +40 -1
- package/lib/public/css/mobile-nav.css +80 -0
- package/lib/public/css/notifications-center.css +67 -0
- package/lib/public/css/pane.css +97 -10
- package/lib/public/css/project-logs.css +198 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/session-actions.css +16 -101
- package/lib/public/css/sidebar.css +103 -0
- package/lib/public/css/sticky-notes.css +237 -229
- package/lib/public/css/worker-proposal.css +36 -3
- package/lib/public/index.html +43 -11
- package/lib/public/modules/admin.js +8 -8
- package/lib/public/modules/app-connection.js +124 -6
- package/lib/public/modules/app-home-hub.js +12 -8
- package/lib/public/modules/app-message-cards.js +2 -1
- package/lib/public/modules/app-messages.js +92 -11
- package/lib/public/modules/app-misc.js +2 -14
- package/lib/public/modules/app-notifications.js +11 -7
- package/lib/public/modules/app-panels.js +3 -2
- package/lib/public/modules/app-projects.js +56 -18
- package/lib/public/modules/app-rendering.js +1 -0
- package/lib/public/modules/capsule-preference.js +44 -0
- package/lib/public/modules/chat-bubble-renderer.js +1 -1
- package/lib/public/modules/clay-log-links.js +70 -0
- package/lib/public/modules/command-palette.js +52 -15
- package/lib/public/modules/context-sources.js +0 -3
- package/lib/public/modules/git-agent-sessions.js +85 -0
- package/lib/public/modules/git-panel.js +111 -84
- package/lib/public/modules/git-placard.js +161 -0
- package/lib/public/modules/home-chat-empty-state.js +39 -0
- package/lib/public/modules/home-chat-identity.js +9 -0
- package/lib/public/modules/home-conversations-sheet.js +102 -48
- package/lib/public/modules/home-mate-chat.js +15 -35
- package/lib/public/modules/home-session-actions.js +6 -0
- package/lib/public/modules/home-sidebar-chat-list.js +101 -41
- package/lib/public/modules/home-sidebar.js +7 -0
- package/lib/public/modules/home-surface-boot.js +7 -3
- package/lib/public/modules/home-tool-frame.js +182 -0
- package/lib/public/modules/home-tools.js +138 -1
- package/lib/public/modules/input.js +38 -7
- package/lib/public/modules/markdown.js +2 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/message-delivery.js +97 -0
- package/lib/public/modules/paste-modal.js +84 -0
- package/lib/public/modules/project-activation.js +45 -0
- package/lib/public/modules/project-logs-render.js +405 -0
- package/lib/public/modules/project-logs.js +461 -0
- package/lib/public/modules/project-removal-target.js +26 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/session-actions.js +29 -105
- package/lib/public/modules/session-hierarchy.js +54 -0
- package/lib/public/modules/sidebar-mobile.js +40 -15
- package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
- package/lib/public/modules/sidebar-sessions.js +77 -11
- package/lib/public/modules/sidebar.js +17 -5
- package/lib/public/modules/split-group-helpers.js +8 -0
- package/lib/public/modules/split-pair-ui.js +15 -4
- package/lib/public/modules/split-view.js +5 -2
- package/lib/public/modules/split-worker-runtime.js +24 -0
- package/lib/public/modules/sticky-note-markdown.js +5 -0
- package/lib/public/modules/sticky-notes-browser.js +326 -0
- package/lib/public/modules/sticky-notes-card.js +360 -0
- package/lib/public/modules/sticky-notes-editor.js +291 -0
- package/lib/public/modules/sticky-notes-shared.js +90 -0
- package/lib/public/modules/sticky-notes.js +170 -946
- package/lib/public/modules/thinking-lifecycle.js +175 -0
- package/lib/public/modules/thinking-summary.js +28 -0
- package/lib/public/modules/thinking-view.js +75 -0
- package/lib/public/modules/tool-palette-order.js +143 -0
- package/lib/public/modules/tool-palette-overlays.js +159 -0
- package/lib/public/modules/tool-palette.js +21 -188
- package/lib/public/modules/tools.js +31 -123
- package/lib/public/modules/update-snooze.js +169 -0
- package/lib/public/modules/user-settings.js +4 -0
- package/lib/public/modules/worker-pane-lock.js +176 -0
- package/lib/public/modules/worker-proposal-state.js +16 -0
- package/lib/public/modules/worker-proposal.js +49 -20
- package/lib/public/style.css +3 -1
- package/lib/sdk-bridge.js +135 -46
- package/lib/sdk-message-processor.js +36 -7
- package/lib/server-experimental-settings.js +49 -0
- package/lib/server-global-ws.js +11 -0
- package/lib/server-home-chat-events.js +31 -1
- package/lib/server-home-chat.js +27 -4
- package/lib/server-home-clay-entry.js +1 -1
- package/lib/server-home-clay-session-links.js +34 -5
- package/lib/server-settings.js +5 -0
- package/lib/server-tools.js +127 -9
- package/lib/server.js +137 -22
- package/lib/session-driver-eligibility.js +38 -0
- package/lib/session-driver-orchestration.js +31 -0
- package/lib/session-hygiene.js +3 -0
- package/lib/session-notes-mcp-server.js +25 -5
- package/lib/session-pair-factory.js +247 -0
- package/lib/session-pair-mcp-server.js +46 -8
- package/lib/session-pair-prompts.js +79 -0
- package/lib/session-pair-turn-control.js +153 -0
- package/lib/session-provenance.js +119 -0
- package/lib/session-spawn-mcp-server.js +1 -1
- package/lib/session-split-groups.js +4 -1
- package/lib/session-title-policy.js +60 -0
- package/lib/session-visibility.js +41 -0
- package/lib/sessions.js +57 -10
- package/lib/tools-registry.js +89 -10
- package/lib/update-snooze.js +437 -0
- package/lib/users-experimental-preferences.js +30 -0
- package/lib/users-permissions.js +6 -6
- package/lib/users.js +22 -16
- package/lib/workspace-query-access.js +102 -0
- package/lib/workspace-query-service.js +24 -17
- package/lib/worktree.js +25 -38
- package/lib/ws-schema.js +38 -7
- package/lib/yoke/adapters/claude-worker.js +16 -6
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex.js +24 -14
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
var usersModule = require("./users");
|
|
2
2
|
var yoke = require("./yoke");
|
|
3
3
|
var backgroundTaskTiming = require("./background-task-timing");
|
|
4
|
+
var sessionTitlePolicy = require("./session-title-policy");
|
|
5
|
+
|
|
6
|
+
var OVERLOAD_RETRY_LIMIT = 3;
|
|
4
7
|
|
|
5
8
|
function attachMessageProcessor(ctx) {
|
|
6
9
|
var sm = ctx.sm;
|
|
@@ -23,8 +26,6 @@ function attachMessageProcessor(ctx) {
|
|
|
23
26
|
var saveImageFile = ctx.saveImageFile;
|
|
24
27
|
var getSessionLinuxUser = ctx.getSessionLinuxUser || function () { return null; };
|
|
25
28
|
|
|
26
|
-
var AUTO_TITLE_TURN_THRESHOLD = 2;
|
|
27
|
-
|
|
28
29
|
function getMateIdForNotification() {
|
|
29
30
|
if (!isMate) return null;
|
|
30
31
|
if (typeof slug === "string" && slug.indexOf("mate-") === 0) {
|
|
@@ -488,6 +489,8 @@ function attachMessageProcessor(ctx) {
|
|
|
488
489
|
}
|
|
489
490
|
|
|
490
491
|
} else if (parsed.yokeType === "result") {
|
|
492
|
+
var overloadAbortRequested = !!session._overloadAbortRequested;
|
|
493
|
+
session._overloadAbortRequested = false;
|
|
491
494
|
session.blocks = {};
|
|
492
495
|
session.sentToolResults = {};
|
|
493
496
|
session.pendingPermissions = {};
|
|
@@ -533,7 +536,9 @@ function attachMessageProcessor(ctx) {
|
|
|
533
536
|
session._awaitingTurnResult = false;
|
|
534
537
|
session._queuedTurnCount = 0;
|
|
535
538
|
onProcessingChanged();
|
|
536
|
-
|
|
539
|
+
if (!overloadAbortRequested) {
|
|
540
|
+
sendAndRecord(session, { type: "error", text: "Claude error: " + execError });
|
|
541
|
+
}
|
|
537
542
|
sendAndRecord(session, { type: "done", code: 1 });
|
|
538
543
|
sm.broadcastSessionList();
|
|
539
544
|
return;
|
|
@@ -625,7 +630,7 @@ function attachMessageProcessor(ctx) {
|
|
|
625
630
|
sm.broadcastSessionList();
|
|
626
631
|
|
|
627
632
|
// Auto-generate title after N turns (skip if loop or already auto-generated)
|
|
628
|
-
if (session.turnCount ===
|
|
633
|
+
if (session.turnCount === sessionTitlePolicy.generationTurn(isMate)
|
|
629
634
|
&& !session.titleAutoGenerated
|
|
630
635
|
&& !session.titleManuallySet
|
|
631
636
|
&& !session.loop
|
|
@@ -820,9 +825,33 @@ function attachMessageProcessor(ctx) {
|
|
|
820
825
|
}
|
|
821
826
|
|
|
822
827
|
} else if (parsed.yokeType === "api_retry") {
|
|
823
|
-
//
|
|
824
|
-
|
|
825
|
-
|
|
828
|
+
// The Claude SDK may otherwise paint one persistent red error for every
|
|
829
|
+
// retry and remain busy for many minutes. Show one transient status, and
|
|
830
|
+
// stop a repeatedly overloaded turn after a small bounded number of
|
|
831
|
+
// attempts so the user regains control and can retry or change models.
|
|
832
|
+
var apiRetryAttempt = parsed.attempt || 1;
|
|
833
|
+
if (parsed.error === "overloaded") {
|
|
834
|
+
if (apiRetryAttempt === 1) {
|
|
835
|
+
session._overloadAbortRequested = false;
|
|
836
|
+
sendToSession(session, {
|
|
837
|
+
type: "system_info",
|
|
838
|
+
text: "The model is overloaded. Retrying briefly...",
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
if (apiRetryAttempt >= OVERLOAD_RETRY_LIMIT && !session._overloadAbortRequested) {
|
|
842
|
+
session._overloadAbortRequested = true;
|
|
843
|
+
sendAndRecord(session, {
|
|
844
|
+
type: "error",
|
|
845
|
+
text: "The model remained overloaded after " + apiRetryAttempt +
|
|
846
|
+
" attempts, so this turn was stopped. Try again or choose another model.",
|
|
847
|
+
});
|
|
848
|
+
if (session.abortController && typeof session.abortController.abort === "function") {
|
|
849
|
+
try { session.abortController.abort(); } catch (e) {}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
} else if (apiRetryAttempt === 1) {
|
|
853
|
+
sendToSession(session, { type: "system_info", text: "The model request failed temporarily. Retrying..." });
|
|
854
|
+
}
|
|
826
855
|
|
|
827
856
|
} else if (parsed.yokeType === "commands_changed") {
|
|
828
857
|
// Mid-session command list change: rebuild the union with skills (same as
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function attachExperimentalSettings(ctx) {
|
|
2
|
+
var users = ctx.users;
|
|
3
|
+
var getMultiUserFromReq = ctx.getMultiUserFromReq;
|
|
4
|
+
var opts = ctx.opts;
|
|
5
|
+
|
|
6
|
+
function handleRequest(req, res, fullUrl) {
|
|
7
|
+
if (req.method !== "PUT" || fullUrl !== "/api/user/capsules-enabled") return false;
|
|
8
|
+
var isMultiUser = users.isMultiUser();
|
|
9
|
+
var mu = getMultiUserFromReq(req);
|
|
10
|
+
if (isMultiUser && !mu) {
|
|
11
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
12
|
+
res.end('{"error":"unauthorized"}');
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
var body = "";
|
|
16
|
+
req.on("data", function (chunk) { body += chunk; });
|
|
17
|
+
req.on("end", function () {
|
|
18
|
+
try {
|
|
19
|
+
var data = JSON.parse(body);
|
|
20
|
+
var result;
|
|
21
|
+
var userId = "default";
|
|
22
|
+
if (isMultiUser) {
|
|
23
|
+
userId = mu.id;
|
|
24
|
+
result = users.setCapsulesEnabled(userId, data.enabled === true);
|
|
25
|
+
} else if (typeof opts.onSetCapsulesEnabled === "function") {
|
|
26
|
+
result = opts.onSetCapsulesEnabled(data.enabled === true);
|
|
27
|
+
} else {
|
|
28
|
+
result = { ok: true, capsulesEnabled: false };
|
|
29
|
+
}
|
|
30
|
+
if (result.error) {
|
|
31
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
32
|
+
res.end(JSON.stringify({ error: result.error }));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeof ctx.onCapsulesPreferenceChanged === "function") ctx.onCapsulesPreferenceChanged(userId);
|
|
36
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
37
|
+
res.end(JSON.stringify({ ok: true, capsulesEnabled: result.capsulesEnabled === true }));
|
|
38
|
+
} catch (e) {
|
|
39
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
40
|
+
res.end('{"error":"Invalid request"}');
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { handleRequest: handleRequest };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { attachExperimentalSettings: attachExperimentalSettings };
|
package/lib/server-global-ws.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// Bound to the slug-less `/ws` endpoint by lib/server.js. Only handles the
|
|
8
8
|
// small set of messages needed to bootstrap into a project context:
|
|
9
9
|
// - ping -> pong keep-alive
|
|
10
|
+
// - Home and Mate -> the same user-scoped handlers as project sockets
|
|
10
11
|
// - browse_dir -> directory picker for the add-project modal
|
|
11
12
|
// - add_project -> register an existing directory
|
|
12
13
|
// - create_project -> make a new empty project
|
|
@@ -37,6 +38,8 @@ function attachGlobalWs(opts) {
|
|
|
37
38
|
var onAddProject = opts.onAddProject;
|
|
38
39
|
var onCreateProject = opts.onCreateProject;
|
|
39
40
|
var onCloneProject = opts.onCloneProject;
|
|
41
|
+
var onHomePreferenceMessage = opts.onHomePreferenceMessage;
|
|
42
|
+
var onAppMessage = opts.onAppMessage;
|
|
40
43
|
|
|
41
44
|
function handleMessage(ws, msg) {
|
|
42
45
|
if (!msg || typeof msg !== "object") return;
|
|
@@ -46,6 +49,14 @@ function attachGlobalWs(opts) {
|
|
|
46
49
|
return;
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
// A user does not need an ordinary project before Home becomes useful.
|
|
53
|
+
// Route Mate discovery, Home chat/debates, and tools through the same
|
|
54
|
+
// handlers used by project sockets. This also lets mate_list repair an
|
|
55
|
+
// existing account whose built-ins were missing from its final storage.
|
|
56
|
+
if (typeof onAppMessage === "function" && onAppMessage(ws, msg)) return;
|
|
57
|
+
|
|
58
|
+
if (typeof onHomePreferenceMessage === "function" && onHomePreferenceMessage(ws, msg)) return;
|
|
59
|
+
|
|
49
60
|
// --- Directory picker for the add-project modal ---
|
|
50
61
|
if (msg.type === "browse_dir") {
|
|
51
62
|
var rawPath = (msg.path || "").replace(/^~/, config.REAL_HOME);
|
|
@@ -134,9 +134,24 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
134
134
|
applyDebateHistoryEvent(messages, event);
|
|
135
135
|
continue;
|
|
136
136
|
}
|
|
137
|
+
if (event.type === "capsule_turn") {
|
|
138
|
+
// A Capsule engagement delivery. The transcript shows a short system
|
|
139
|
+
// note; the full delivery prompt is model-facing, not conversation.
|
|
140
|
+
flushAssistant();
|
|
141
|
+
messages.push({
|
|
142
|
+
role: "capsule_turn",
|
|
143
|
+
text: (event.toolName || event.toolId || "Capsule") + (event.kind === "start" ? ": a new game started." : ": your Mate is taking its turn."),
|
|
144
|
+
});
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
137
147
|
if (event.type === "user_message" && event.text && event.askUserAnswer !== true && !interviewMode) {
|
|
138
148
|
flushAssistant();
|
|
139
149
|
messages.push({ role: "user", text: event.text });
|
|
150
|
+
} else if (!interviewMode && (event.type === "tool_start" || event.type === "tool_executing" || event.type === "tool_result")) {
|
|
151
|
+
// A tool call ends the current spoken burst. Without this flush the
|
|
152
|
+
// text on both sides of the call concatenates into one run-on bubble,
|
|
153
|
+
// which is exactly how a Capsule game transcript turns into a wall.
|
|
154
|
+
flushAssistant();
|
|
140
155
|
} else if (event.type === "delta" && typeof event.text === "string" && !interviewMode) {
|
|
141
156
|
pending += event.text;
|
|
142
157
|
} else if (event.type === "result" || event.type === "done") {
|
|
@@ -185,13 +200,17 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
185
200
|
return messages;
|
|
186
201
|
}
|
|
187
202
|
|
|
203
|
+
// The authoritative text for the bubble being finalized: only the deltas
|
|
204
|
+
// since the last conversational boundary. Tool calls and Capsule turn
|
|
205
|
+
// deliveries are boundaries too, or a session that is never driven by typed
|
|
206
|
+
// user messages (a Capsule game) would collapse into one run-on bubble.
|
|
188
207
|
function latestAssistantText(history) {
|
|
189
208
|
var text = "";
|
|
190
209
|
for (var i = (history || []).length - 1; i >= 0; i--) {
|
|
191
210
|
var event = history[i];
|
|
192
211
|
if (!event) continue;
|
|
193
212
|
if (event.type === "delta" && typeof event.text === "string") text = event.text + text;
|
|
194
|
-
if (event.type === "user_message" || event.type === "
|
|
213
|
+
if (event.type === "user_message" || event.type === "capsule_turn" || event.type === "tool_start" || event.type === "tool_executing" || event.type === "tool_result" || event.type === "debate_proposal" || event.type === "debate_proposal_resolved" || event.type === "project_assignment_proposal" || event.type === "project_assignment_status") break;
|
|
195
214
|
}
|
|
196
215
|
return text;
|
|
197
216
|
}
|
|
@@ -209,6 +228,9 @@ function searchToolLabel(name, input) {
|
|
|
209
228
|
if (name === "list_project_sessions") return "Reviewing project conversations";
|
|
210
229
|
if (name === "list_projects") return "Reviewing your projects";
|
|
211
230
|
if (name === "search_project_history") return query ? "Searching a project for \u201c" + query + "\u201d" : "Searching a project";
|
|
231
|
+
if (name === "search_project_logs") return query ? "Searching project logs for \u201c" + query + "\u201d" : "Searching project logs";
|
|
232
|
+
if (name === "list_project_logs") return "Reviewing project logs";
|
|
233
|
+
if (name === "read_project_log" || name === "read_project_log_revision" || name === "project_log_history") return "Reading a project log";
|
|
212
234
|
return "Using " + (cleanActivityText(name, 64) || "a workspace tool");
|
|
213
235
|
}
|
|
214
236
|
|
|
@@ -281,6 +303,14 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
|
|
|
281
303
|
if (session && session.mateCreationMode === true && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) return Object.assign({ type: "home_mate_creation_question", toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
282
304
|
if (session && session.mateCreationMode === true && event.type === "ask_user_answered" && event.toolId) return Object.assign({ type: "home_mate_creation_question_resolved", toolId: event.toolId, status: "answered", answers: event.answers || null }, metadata);
|
|
283
305
|
if (session && session.mateCreationMode === true && event.type === "home_mate_creation_question_expired" && event.toolId) return Object.assign({ type: "home_mate_creation_question_resolved", toolId: event.toolId, status: "expired", error: event.error || "This question expired. Ask Clay to repeat it." }, metadata);
|
|
306
|
+
if ((event.type === "tool_start" || event.type === "tool_executing") && event.name !== "AskUserQuestion") {
|
|
307
|
+
// A tool call ends the current spoken burst: the client seals the bubble
|
|
308
|
+
// it has streamed so far, and later text starts a fresh one. Without this
|
|
309
|
+
// a session driven by tool play (a Capsule game) streams into one
|
|
310
|
+
// ever-growing run-on bubble. Last so every special surface above (search
|
|
311
|
+
// activity, debates, interviews, AskUserQuestion) keeps precedence.
|
|
312
|
+
return Object.assign({ type: "home_mate_segment" }, metadata);
|
|
313
|
+
}
|
|
284
314
|
return null;
|
|
285
315
|
}
|
|
286
316
|
|
package/lib/server-home-chat.js
CHANGED
|
@@ -9,6 +9,8 @@ var attachHomeMateCreation = require("./server-home-mate-creation").attachHomeMa
|
|
|
9
9
|
var attachHomeDebates = require("./server-home-debates").attachHomeDebates, attachHomeClayEntry = require("./server-home-clay-entry").attachHomeClayEntry;
|
|
10
10
|
var homeChatEvents = require("./server-home-chat-events");
|
|
11
11
|
var homeCapsuleCreation = require("./server-home-capsule-creation");
|
|
12
|
+
var sessionTitlePolicy = require("./session-title-policy");
|
|
13
|
+
var sessionProvenance = require("./session-provenance");
|
|
12
14
|
var historyToHomeChat = homeChatEvents.historyToHomeChat;
|
|
13
15
|
var transformEvent = homeChatEvents.transformEvent;
|
|
14
16
|
function attachHomeChat(deps) {
|
|
@@ -82,8 +84,18 @@ function attachHomeChat(deps) {
|
|
|
82
84
|
var sessionManager = found.ctx.getSessionManager();
|
|
83
85
|
if (!sessionManager) return [];
|
|
84
86
|
var result = [];
|
|
87
|
+
var visibleSessions = [];
|
|
85
88
|
sessionManager.sessions.forEach(function (session) {
|
|
86
89
|
if (!ownsSession(session, userId)) return;
|
|
90
|
+
visibleSessions.push(session);
|
|
91
|
+
});
|
|
92
|
+
var hierarchy = sessionProvenance.hierarchyFor(visibleSessions);
|
|
93
|
+
for (var vi = 0; vi < visibleSessions.length; vi++) {
|
|
94
|
+
var session = visibleSessions[vi];
|
|
95
|
+
if (sessionTitlePolicy.repairLegacySearchTitle(session)
|
|
96
|
+
&& typeof sessionManager.saveSessionFile === "function") {
|
|
97
|
+
sessionManager.saveSessionFile(session);
|
|
98
|
+
}
|
|
87
99
|
var cliSessionId = sessionString(session.cliSessionId, 512);
|
|
88
100
|
var createdAt = sessionTimestamp(session.createdAt);
|
|
89
101
|
var lastActivity = sessionTimestamp(session.lastActivity) || createdAt;
|
|
@@ -97,12 +109,16 @@ function attachHomeChat(deps) {
|
|
|
97
109
|
createdAt: createdAt,
|
|
98
110
|
lastActivity: lastActivity,
|
|
99
111
|
isProcessing: !!session.isProcessing,
|
|
112
|
+
sessionRole: hierarchy[session.localId].role,
|
|
113
|
+
parentSessionId: hierarchy[session.localId].parentSessionId == null ? null : sessionReference(sessionManager.sessions.get(hierarchy[session.localId].parentSessionId)),
|
|
114
|
+
parentAvailable: hierarchy[session.localId].parentAvailable,
|
|
115
|
+
workerGeneration: hierarchy[session.localId].generation,
|
|
100
116
|
});
|
|
101
117
|
if (session.debateSetupMode === true) result[result.length - 1].debatePlanning = true;
|
|
102
118
|
if (session.homeDebatePhase) result[result.length - 1].debatePhase = session.homeDebatePhase;
|
|
103
119
|
if (session.mateCreationMode === true) result[result.length - 1].mateCreation = true;
|
|
104
120
|
if (session.homeMateCreationPhase) result[result.length - 1].mateCreationPhase = session.homeMateCreationPhase;
|
|
105
|
-
}
|
|
121
|
+
}
|
|
106
122
|
result.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
107
123
|
return result;
|
|
108
124
|
}
|
|
@@ -188,7 +204,12 @@ function attachHomeChat(deps) {
|
|
|
188
204
|
|
|
189
205
|
var homeModels = attachHomeModels({ users: users, mates: mates, projects: projects, sendMessage: sendMessage });
|
|
190
206
|
var homeDebates = attachHomeDebates({ mates: mates, findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, sendMessage: sendMessage });
|
|
191
|
-
var homeClaySessionLinks = attachHomeClaySessionLinks({
|
|
207
|
+
var homeClaySessionLinks = attachHomeClaySessionLinks({
|
|
208
|
+
projects: projects,
|
|
209
|
+
workspaceQueryService: deps.workspaceQueryService,
|
|
210
|
+
projectLogsService: deps.projectLogsService,
|
|
211
|
+
sendMessage: sendMessage,
|
|
212
|
+
});
|
|
192
213
|
|
|
193
214
|
function sendHistory(ws, found, session, requestId) {
|
|
194
215
|
if (ws.readyState !== 1) return;
|
|
@@ -367,7 +388,7 @@ function attachHomeChat(deps) {
|
|
|
367
388
|
|
|
368
389
|
function handleMessage(ws, msg) {
|
|
369
390
|
if (!msg || typeof msg.type !== "string") return false;
|
|
370
|
-
if (msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
391
|
+
if (msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
371
392
|
return false;
|
|
372
393
|
}
|
|
373
394
|
|
|
@@ -386,6 +407,7 @@ function attachHomeChat(deps) {
|
|
|
386
407
|
if (users.isMultiUser() && !userId) {
|
|
387
408
|
if (msg.type === "home_debates_list") sendMessage(ws, { type: "home_debates_state", requestId: msg.requestId || null, status: "error", debates: [], error: "Sign in to load your debates." });
|
|
388
409
|
else if (msg.type === "home_clay_session_resolve") sendMessage(ws, { type: "home_clay_session_target", requestId: msg.requestId || null, sessionRef: msg.sessionRef || null, status: "error", error: "Sign in to open this session." });
|
|
410
|
+
else if (msg.type === "home_clay_log_resolve") sendMessage(ws, { type: "home_clay_log_target", requestId: msg.requestId || null, ref: msg.ref || null, status: "error", error: "Sign in to open this log." });
|
|
389
411
|
else if (msg.type === "home_mate_models_get" || msg.type === "home_mate_model_set") homeModels.sendAccessError(ws, msg, "Not authenticated.");
|
|
390
412
|
else sendError(ws, msg.mateId || null, "Not authenticated.", msg.requestId || null, msg.sessionId || null);
|
|
391
413
|
return true;
|
|
@@ -394,6 +416,7 @@ function attachHomeChat(deps) {
|
|
|
394
416
|
if (homeDebates.handle(ws, userId, msg)) return true;
|
|
395
417
|
if (msg.type === "home_clay_ask") { homeClayEntry.start(ws, userId, msg); return true; }
|
|
396
418
|
if (msg.type === "home_clay_session_resolve") { homeClaySessionLinks.resolve(ws, msg); return true; }
|
|
419
|
+
if (msg.type === "home_clay_log_resolve") { homeClaySessionLinks.resolveLog(ws, msg); return true; }
|
|
397
420
|
|
|
398
421
|
if (msg.type === "home_mate_debate_plan") {
|
|
399
422
|
homeDebate.start(ws, userId, msg);
|
|
@@ -513,6 +536,6 @@ function attachHomeChat(deps) {
|
|
|
513
536
|
teardownTap(ws);
|
|
514
537
|
teardownTap(ws, "_searchClayTap");
|
|
515
538
|
}
|
|
516
|
-
return { handleMessage: handleMessage, handleDisconnection: handleDisconnection };
|
|
539
|
+
return { handleMessage: handleMessage, handleDisconnection: handleDisconnection, findMateProject: findMateProject };
|
|
517
540
|
}
|
|
518
541
|
module.exports = { attachHomeChat: attachHomeChat };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
function attachHomeClayEntry(ctx) {
|
|
4
4
|
function providerPrompt(text) {
|
|
5
|
-
return "This conversation began in Clay Studio's global search. Respond as Clay. When the user is trying to locate
|
|
5
|
+
return "This conversation began in Clay Studio's global search. Respond as Clay. When the user is trying to locate a conversation, use search_workspace_history before any other investigation. When the user asks about a project's prior work, decisions, defects, status, rationale, or unfinished work, identify the project and search_project_logs before answering; use conversation history as additional evidence when useful. Search by meaning, related terms, and context, using at most three focused search passes. Do not use Bash, filesystem scans, or generic agents to search Clay history. Give the user useful findings promptly, and do not mention tools or internal search mechanics. Do not force a workspace or Logs search when the request is a general question or task.\n\nUser request:\n" + text;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
function findExisting(manager, userId, requestId) {
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
// Resolve rendered Mate session references through an exact
|
|
1
|
+
// Resolve rendered Mate session and Project Log references through an exact
|
|
2
|
+
// owner-bound source session.
|
|
2
3
|
|
|
3
4
|
function attachHomeClaySessionLinks(ctx) {
|
|
4
|
-
function
|
|
5
|
+
function source(ws, msg) {
|
|
5
6
|
var tap = msg.surface === "search" ? ws._searchClayTap : ws._homeChatTap;
|
|
6
7
|
var sourceProject = tap && tap.mateSlug ? ctx.projects.get(tap.mateSlug) : null;
|
|
7
8
|
var sourceManager = sourceProject && sourceProject.getSessionManager ? sourceProject.getSessionManager() : null;
|
|
8
9
|
var sourceSession = sourceManager && tap ? sourceManager.sessions.get(tap.sessionId) : null;
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
return { tap: tap, project: sourceProject, session: sourceSession };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolve(ws, msg) {
|
|
14
|
+
var selected = source(ws, msg);
|
|
15
|
+
var bound = ctx.workspaceQueryService && selected.session
|
|
16
|
+
? ctx.workspaceQueryService.bindProjectSession({ projectSlug: selected.tap.mateSlug, session: selected.session })
|
|
11
17
|
: null;
|
|
12
18
|
var payload = { type: "home_clay_session_target", requestId: msg.requestId || null, sessionRef: msg.sessionRef || null, status: "error" };
|
|
13
19
|
try {
|
|
@@ -20,7 +26,30 @@ function attachHomeClaySessionLinks(ctx) {
|
|
|
20
26
|
ctx.sendMessage(ws, payload);
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
function resolveLog(ws, msg) {
|
|
30
|
+
var selected = source(ws, msg);
|
|
31
|
+
var status = selected.project && selected.project.getStatus ? selected.project.getStatus() : null;
|
|
32
|
+
var bound = ctx.projectLogsService && selected.session && status
|
|
33
|
+
? ctx.projectLogsService.bindMate({
|
|
34
|
+
projectSlug: selected.tap.mateSlug,
|
|
35
|
+
projectOwnerId: status.projectOwnerId || null,
|
|
36
|
+
isMate: true,
|
|
37
|
+
mateId: selected.tap.mateId,
|
|
38
|
+
session: selected.session,
|
|
39
|
+
})
|
|
40
|
+
: null;
|
|
41
|
+
var payload = { type: "home_clay_log_target", requestId: msg.requestId || null, ref: msg.ref || null, status: "error" };
|
|
42
|
+
try {
|
|
43
|
+
if (!bound) throw new Error("The source conversation is no longer available.");
|
|
44
|
+
payload.target = bound.resolveLogNavigation({ ref: msg.ref });
|
|
45
|
+
payload.status = "ready";
|
|
46
|
+
} catch (error) {
|
|
47
|
+
payload.error = error.message || "Log not available.";
|
|
48
|
+
}
|
|
49
|
+
ctx.sendMessage(ws, payload);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { resolve: resolve, resolveLog: resolveLog };
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
module.exports = { attachHomeClaySessionLinks: attachHomeClaySessionLinks };
|
package/lib/server-settings.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var fs = require("fs");
|
|
2
2
|
var path = require("path");
|
|
3
|
+
var { attachExperimentalSettings } = require("./server-experimental-settings");
|
|
3
4
|
|
|
4
5
|
function attachSettings(ctx) {
|
|
5
6
|
var users = ctx.users;
|
|
@@ -10,8 +11,10 @@ function attachSettings(ctx) {
|
|
|
10
11
|
var CONFIG_DIR = ctx.CONFIG_DIR;
|
|
11
12
|
|
|
12
13
|
var profilePath = path.join(CONFIG_DIR, "profile.json");
|
|
14
|
+
var experimentalSettings = attachExperimentalSettings(ctx);
|
|
13
15
|
|
|
14
16
|
function handleRequest(req, res, fullUrl) {
|
|
17
|
+
if (experimentalSettings.handleRequest(req, res, fullUrl)) return true;
|
|
15
18
|
// GET /api/profile
|
|
16
19
|
if (req.method === "GET" && fullUrl === "/api/profile") {
|
|
17
20
|
if (users.isMultiUser()) {
|
|
@@ -30,6 +33,7 @@ function attachSettings(ctx) {
|
|
|
30
33
|
profile.chatLayout = mu.chatLayout || "channel";
|
|
31
34
|
profile.mateOnboardingShown = !!mu.mateOnboardingShown;
|
|
32
35
|
profile.matesEnabled = mu.matesEnabled === true;
|
|
36
|
+
profile.capsulesEnabled = users.getCapsulesEnabled(mu.id);
|
|
33
37
|
try { profile.terminalFont = users.getTerminalFont(mu.id); } catch (e) {}
|
|
34
38
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
35
39
|
res.end(JSON.stringify(profile));
|
|
@@ -53,6 +57,7 @@ function attachSettings(ctx) {
|
|
|
53
57
|
profile.chatLayout = dc.chatLayout || "channel";
|
|
54
58
|
profile.mateOnboardingShown = !!dc.mateOnboardingShown;
|
|
55
59
|
profile.matesEnabled = dc.matesEnabled === true;
|
|
60
|
+
profile.capsulesEnabled = dc.capsulesEnabled === true;
|
|
56
61
|
if (dc.terminalFont && typeof dc.terminalFont === "object") {
|
|
57
62
|
profile.terminalFont = {
|
|
58
63
|
family: dc.terminalFont.family || "'SF Mono', Menlo, Monaco, 'Courier New', monospace",
|