clay-server 3.8.1 → 4.0.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.
- package/lib/ask-user-mcp-server.js +5 -119
- 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 +1 -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/mate-creation-mcp-server.js +55 -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-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 +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -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-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +329 -102
- package/lib/public/app.js +85 -42
- 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/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- 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 +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- 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 +78 -20
- package/lib/public/modules/app-notifications.js +4 -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/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 +158 -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-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/profile.js +4 -5
- 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/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 +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/sticky-notes.js +7 -6
- 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-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/user-settings.js +16 -23
- 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 +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- 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 +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- 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 +276 -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 +86 -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 +73 -43
- package/lib/yoke/adapters/codex.js +37 -6
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- 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 +2 -1
- 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,84 @@
|
|
|
1
|
+
function hasEntries(value) {
|
|
2
|
+
return !!(value && Object.keys(value).length > 0);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function unsafeReason(session, isPaired) {
|
|
6
|
+
if (!session || session.hidden) return "Target session is unavailable.";
|
|
7
|
+
if (!session.cliSessionId) return "Target session must have a durable session reference.";
|
|
8
|
+
if (session.sessionVisibility !== "private") return "Target session must be private.";
|
|
9
|
+
if (session.isProcessing || session._queryStarting || session._awaitingTurnResult) return "Target session must be idle.";
|
|
10
|
+
if (hasEntries(session.pendingPermissions) || hasEntries(session.pendingAskUser) || hasEntries(session.pendingElicitations) || hasEntries(session.pendingUserDialogs)) return "Target session is waiting for user input.";
|
|
11
|
+
if ((session.mode && session.mode !== "gui") || (session.runtimeMode && session.runtimeMode !== "gui") || session.terminalId != null || session.runtimeTerminalId != null || session.tuiSuspended) return "Terminal sessions cannot receive project follow-ups.";
|
|
12
|
+
if (session.homeDebatePlanning || session.homeDebatePhase || session.debateSetupMode || session.debateState || session._debate) return "Debate sessions cannot receive project follow-ups.";
|
|
13
|
+
if (session.loop || session.spawn || session.handoff || session.assignment || session.singleTurn || session._pairDelegation || isPaired) return "Orchestrated sessions cannot receive project follow-ups.";
|
|
14
|
+
if (session.dangerouslySkipPermissions || session.permissionMode === "bypassPermissions") return "Full-access sessions cannot receive project follow-ups.";
|
|
15
|
+
if (session.destroying || session.scheduledMessage || session.rateLimitAutoContinuePending || session.taskStopRequested || session._runtimeRefreshRequested || session.pendingPush && session.pendingPush.length) return "Target session is not safely resumable right now.";
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function attachDelegatedFollowUp(ctx) {
|
|
20
|
+
var sm = ctx.sm;
|
|
21
|
+
|
|
22
|
+
function inspect(principal, targetSessionRef) {
|
|
23
|
+
if (!principal || typeof targetSessionRef !== "string" || targetSessionRef.indexOf("session:") !== 0) {
|
|
24
|
+
throw new Error("A durable opaque targetSessionRef is required.");
|
|
25
|
+
}
|
|
26
|
+
var session = null;
|
|
27
|
+
sm.sessions.forEach(function (candidate) {
|
|
28
|
+
if (!session && ctx.sessionRef(candidate) === targetSessionRef) session = candidate;
|
|
29
|
+
});
|
|
30
|
+
if (!session) throw new Error("Target session was not found in this project.");
|
|
31
|
+
if (ctx.isMultiUser()) {
|
|
32
|
+
if (!principal.userId || session.ownerId !== principal.userId) throw new Error("Target session access denied.");
|
|
33
|
+
} else if (session.ownerId) {
|
|
34
|
+
throw new Error("Target session access denied.");
|
|
35
|
+
}
|
|
36
|
+
var paired = !!(ctx.isPairedSession && ctx.isPairedSession(session));
|
|
37
|
+
var reason = unsafeReason(session, paired);
|
|
38
|
+
if (reason) throw new Error(reason);
|
|
39
|
+
if (!ctx.canResumeVendor(session.vendor)) throw new Error("Target session provider cannot safely resume this conversation.");
|
|
40
|
+
return { session: session, sessionRef: targetSessionRef, title: session.title || "Existing session" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function dispatch(principal, targetSessionRef, task, metadata, onReady) {
|
|
44
|
+
var resolved = inspect(principal, targetSessionRef);
|
|
45
|
+
var session = resolved.session;
|
|
46
|
+
var sdk = ctx.getSdk();
|
|
47
|
+
if (!sdk || typeof sdk.pushMessage !== "function" || typeof sdk.startQuery !== "function") {
|
|
48
|
+
throw new Error("Target project runtime is unavailable.");
|
|
49
|
+
}
|
|
50
|
+
if (typeof onReady === "function") onReady(session);
|
|
51
|
+
sm.sendAndRecord(session, {
|
|
52
|
+
type: "delegated_follow_up",
|
|
53
|
+
text: task,
|
|
54
|
+
assignmentId: metadata.assignmentId,
|
|
55
|
+
sourceMateId: metadata.sourceMateId,
|
|
56
|
+
sourceProjectSlug: metadata.sourceProjectSlug,
|
|
57
|
+
sourceSessionRef: metadata.sourceSessionRef,
|
|
58
|
+
});
|
|
59
|
+
session.isProcessing = true;
|
|
60
|
+
session.lastActivity = Date.now();
|
|
61
|
+
session.sentToolResults = {};
|
|
62
|
+
if (ctx.onProcessingChanged) ctx.onProcessingChanged();
|
|
63
|
+
sm.broadcastSessionList();
|
|
64
|
+
try {
|
|
65
|
+
var delivered = sdk.pushMessage(session, task);
|
|
66
|
+
if (!delivered) await sdk.startQuery(session, task, undefined, ctx.getLinuxUserForSession(session));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
session.isProcessing = false;
|
|
69
|
+
sm.sendAndRecord(session, {
|
|
70
|
+
type: "error",
|
|
71
|
+
text: "Delegated follow-up could not start: " + (error.message || String(error)),
|
|
72
|
+
assignmentId: metadata.assignmentId,
|
|
73
|
+
});
|
|
74
|
+
if (ctx.onProcessingChanged) ctx.onProcessingChanged();
|
|
75
|
+
sm.broadcastSessionList();
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
return session;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { inspectDelegatedFollowUp: inspect, dispatchDelegatedFollowUp: dispatch };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = { attachDelegatedFollowUp: attachDelegatedFollowUp, unsafeReason: unsafeReason };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function attachDelegatedSession(ctx) {
|
|
2
|
+
var sm = ctx.sm;
|
|
3
|
+
|
|
4
|
+
async function createDelegatedSession(principal, task, metadata, onCreated) {
|
|
5
|
+
if (!principal || !task) throw new Error("A bound owner and task are required.");
|
|
6
|
+
var selection = await ctx.resolveModel(principal);
|
|
7
|
+
if (!selection || selection.status !== "ready" || !selection.vendor || !selection.model) {
|
|
8
|
+
throw new Error(selection && selection.error ? selection.error : "No configured model is available in the target project.");
|
|
9
|
+
}
|
|
10
|
+
var sdk = ctx.getSdk();
|
|
11
|
+
if (!sdk || typeof sdk.startQuery !== "function") throw new Error("Target project runtime is unavailable.");
|
|
12
|
+
var create = typeof sm.createSessionRaw === "function" ? sm.createSessionRaw : sm.createSession;
|
|
13
|
+
var session = create.call(sm, {
|
|
14
|
+
ownerId: principal.userId || null,
|
|
15
|
+
sessionVisibility: "private",
|
|
16
|
+
vendor: selection.vendor,
|
|
17
|
+
model: selection.model,
|
|
18
|
+
});
|
|
19
|
+
session.title = metadata.title;
|
|
20
|
+
session.assignment = {
|
|
21
|
+
assignmentId: metadata.assignmentId,
|
|
22
|
+
sourceMateId: metadata.sourceMateId,
|
|
23
|
+
sourceProjectSlug: metadata.sourceProjectSlug,
|
|
24
|
+
sourceSessionRef: metadata.sourceSessionRef,
|
|
25
|
+
delegated: true,
|
|
26
|
+
};
|
|
27
|
+
session.singleTurn = true;
|
|
28
|
+
if (typeof onCreated === "function") onCreated(session);
|
|
29
|
+
sm.sendAndRecord(session, {
|
|
30
|
+
type: "delegated_work",
|
|
31
|
+
text: task,
|
|
32
|
+
assignmentId: metadata.assignmentId,
|
|
33
|
+
sourceMateId: metadata.sourceMateId,
|
|
34
|
+
sourceProjectSlug: metadata.sourceProjectSlug,
|
|
35
|
+
sourceSessionRef: metadata.sourceSessionRef,
|
|
36
|
+
});
|
|
37
|
+
session.isProcessing = true;
|
|
38
|
+
session.lastActivity = Date.now();
|
|
39
|
+
session.sentToolResults = {};
|
|
40
|
+
sm.broadcastSessionList();
|
|
41
|
+
try {
|
|
42
|
+
await Promise.resolve(sdk.startQuery(session, task, undefined, ctx.getLinuxUserForSession(session)));
|
|
43
|
+
} catch (error) {
|
|
44
|
+
session.isProcessing = false;
|
|
45
|
+
sm.sendAndRecord(session, { type: "error", text: error.message || String(error) });
|
|
46
|
+
}
|
|
47
|
+
return session;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { createDelegatedSession: createDelegatedSession };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { attachDelegatedSession: attachDelegatedSession };
|
|
@@ -13,7 +13,7 @@ var execFileSync = require("child_process").execFileSync;
|
|
|
13
13
|
* getOsUserInfoForWs (function)
|
|
14
14
|
* startFileWatch, stopFileWatch, startDirWatch (from _fileWatch)
|
|
15
15
|
* usersModule, fsAsUser
|
|
16
|
-
* validateEnvString (
|
|
16
|
+
* validateEnvString, onEnvironmentChanged (functions)
|
|
17
17
|
* opts (for onGetProjectEnv, onSetProjectEnv, onGetSharedEnv, onSetSharedEnv callbacks)
|
|
18
18
|
* IGNORED_DIRS, BINARY_EXTS, IMAGE_EXTS, FS_MAX_SIZE (constants)
|
|
19
19
|
*/
|
|
@@ -33,6 +33,7 @@ function attachFilesystem(ctx) {
|
|
|
33
33
|
var usersModule = ctx.usersModule;
|
|
34
34
|
var fsAsUser = ctx.fsAsUser;
|
|
35
35
|
var validateEnvString = ctx.validateEnvString;
|
|
36
|
+
var onEnvironmentChanged = ctx.onEnvironmentChanged || function () {};
|
|
36
37
|
var opts = ctx.opts;
|
|
37
38
|
var IGNORED_DIRS = ctx.IGNORED_DIRS;
|
|
38
39
|
var BINARY_EXTS = ctx.BINARY_EXTS;
|
|
@@ -234,16 +235,11 @@ function attachFilesystem(ctx) {
|
|
|
234
235
|
// --- Project environment variables ---
|
|
235
236
|
if (msg.type === "get_project_env") {
|
|
236
237
|
var envrc = "";
|
|
237
|
-
var hasEnvrc = false;
|
|
238
238
|
if (typeof opts.onGetProjectEnv === "function") {
|
|
239
239
|
var envResult = opts.onGetProjectEnv(msg.slug);
|
|
240
240
|
envrc = envResult.envrc || "";
|
|
241
241
|
}
|
|
242
|
-
|
|
243
|
-
var envrcPath = path.join(cwd, ".envrc");
|
|
244
|
-
hasEnvrc = fs.existsSync(envrcPath);
|
|
245
|
-
} catch (e) {}
|
|
246
|
-
sendTo(ws, { type: "project_env_result", slug: msg.slug, envrc: envrc, hasEnvrc: hasEnvrc });
|
|
242
|
+
sendTo(ws, { type: "project_env_result", slug: msg.slug, envrc: envrc });
|
|
247
243
|
return true;
|
|
248
244
|
}
|
|
249
245
|
|
|
@@ -255,7 +251,8 @@ function attachFilesystem(ctx) {
|
|
|
255
251
|
return true;
|
|
256
252
|
}
|
|
257
253
|
var setResult = opts.onSetProjectEnv(msg.slug, msg.envrc || "");
|
|
258
|
-
|
|
254
|
+
if (setResult.ok) onEnvironmentChanged();
|
|
255
|
+
sendTo(ws, { type: "set_project_env_result", ok: setResult.ok, slug: msg.slug, error: setResult.error, timing: setResult.ok ? "Applies to newly created coding-agent processes. Active processes keep their current environment." : undefined });
|
|
259
256
|
} else {
|
|
260
257
|
sendTo(ws, { type: "set_project_env_result", ok: false, error: "Not supported" });
|
|
261
258
|
}
|
|
@@ -308,7 +305,8 @@ function attachFilesystem(ctx) {
|
|
|
308
305
|
return true;
|
|
309
306
|
}
|
|
310
307
|
var sharedSetResult = opts.onSetSharedEnv(msg.envrc || "");
|
|
311
|
-
|
|
308
|
+
if (sharedSetResult.ok) onEnvironmentChanged();
|
|
309
|
+
sendTo(ws, { type: "set_shared_env_result", ok: sharedSetResult.ok, error: sharedSetResult.error, timing: sharedSetResult.ok ? "Applies to newly created coding-agent processes. Active processes keep their current environment." : undefined });
|
|
312
310
|
} else {
|
|
313
311
|
sendTo(ws, { type: "set_shared_env_result", ok: false, error: "Not supported" });
|
|
314
312
|
}
|
package/lib/project-knowledge.js
CHANGED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
var mateCreationMcp = require("./mate-creation-mcp-server");
|
|
2
|
+
var selectCatalogModel = require("./project-models").selectCatalogModel;
|
|
3
|
+
|
|
4
|
+
function attachMateCreationProposal(ctx) {
|
|
5
|
+
var pending = {};
|
|
6
|
+
|
|
7
|
+
function clean(value, maxLength) {
|
|
8
|
+
if (typeof value !== "string") return "";
|
|
9
|
+
return value.replace(/\u0000/g, "").trim().slice(0, maxLength);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function publicProposal(source) {
|
|
13
|
+
return {
|
|
14
|
+
proposalId: source.proposalId,
|
|
15
|
+
name: clean(source.name, 80),
|
|
16
|
+
bio: clean(source.bio, 280),
|
|
17
|
+
relationship: clean(source.relationship, 120),
|
|
18
|
+
activities: Array.isArray(source.activities) ? source.activities.slice(0, 12) : [],
|
|
19
|
+
communicationStyle: Array.isArray(source.communicationStyle) ? source.communicationStyle.slice(0, 12) : [],
|
|
20
|
+
autonomy: clean(source.autonomy, 500),
|
|
21
|
+
identityMarkdown: clean(source.identityMarkdown, 30000),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function record(session, event) {
|
|
26
|
+
if (typeof ctx.recordSessionEvent === "function") ctx.recordSessionEvent(session, event);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function validateBoundSession(session) {
|
|
30
|
+
var projectOwnerId = typeof ctx.getProjectOwnerId === "function" ? ctx.getProjectOwnerId() : null;
|
|
31
|
+
var ownerValid = typeof ctx.isMultiUser === "function" && ctx.isMultiUser() ? !!(session && session.ownerId && (!projectOwnerId || session.ownerId === projectOwnerId)) : !!(session && !session.ownerId);
|
|
32
|
+
return !!(session && ctx.isMate === true && ctx.isHostAgent === true && session.mateCreationMode === true
|
|
33
|
+
&& ownerValid);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function hasInterviewAnswer(session) {
|
|
37
|
+
var history = session && Array.isArray(session.history) ? session.history : [];
|
|
38
|
+
for (var i = history.length - 1; i >= 0; i--) if (history[i] && history[i].type === "ask_user_answered") return true;
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getToolDefs(boundSession) {
|
|
43
|
+
if (!boundSession || boundSession.mateCreationMode !== true) return [];
|
|
44
|
+
return mateCreationMcp.getToolDefs(function (definition) {
|
|
45
|
+
if (!validateBoundSession(boundSession)) return Promise.resolve({ action: "error", error: "Mate proposals require an owned Clay creation interview." });
|
|
46
|
+
if (!hasInterviewAnswer(boundSession)) return Promise.resolve({ action: "error", error: "Interview the user before proposing a Mate." });
|
|
47
|
+
return new Promise(function (resolve) {
|
|
48
|
+
var proposalId = "mp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
49
|
+
definition.proposalId = proposalId;
|
|
50
|
+
pending[proposalId] = { resolve: resolve, definition: definition, session: boundSession };
|
|
51
|
+
record(boundSession, { type: "mate_creation_proposal", proposal: publicProposal(definition) });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createMcpServer(adapter, boundSession) {
|
|
57
|
+
return adapter.createToolServer({ name: "clay-mate-creation", version: "1.0.0", tools: getToolDefs(boundSession) });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getBridgeTools(boundSession, normalizeSchema) {
|
|
61
|
+
if (!boundSession) return [];
|
|
62
|
+
return getToolDefs(boundSession).map(function (tool) {
|
|
63
|
+
return { server: "clay-mate-creation", name: tool.name, description: tool.description || tool.name, inputSchema: normalizeSchema(tool.inputSchema) };
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function callBridgeTool(boundSession, toolName, args) {
|
|
68
|
+
var tools = getToolDefs(boundSession);
|
|
69
|
+
for (var i = 0; i < tools.length; i++) if (tools[i].name === toolName) return Promise.resolve(tools[i].handler(args || {}));
|
|
70
|
+
return Promise.reject(new Error("Session tool not found: clay-mate-creation/" + toolName));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function handleHomeMessage(ws, msg, session) {
|
|
74
|
+
var entry = msg && msg.proposalId ? pending[msg.proposalId] : null;
|
|
75
|
+
if (!entry || entry.session !== session || !validateBoundSession(session)) return false;
|
|
76
|
+
delete pending[msg.proposalId];
|
|
77
|
+
if (msg.action !== "create") {
|
|
78
|
+
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "cancel" });
|
|
79
|
+
entry.resolve({ action: "cancel" });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (typeof ctx.createReadyMate !== "function") {
|
|
83
|
+
var unavailable = "Mate creation is unavailable.";
|
|
84
|
+
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "error", error: unavailable });
|
|
85
|
+
entry.resolve({ action: "error", error: unavailable });
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
var vendor = session.vendor || "claude";
|
|
89
|
+
if (typeof ctx.getVendorModelCatalog !== "function") {
|
|
90
|
+
var catalogUnavailable = "The Mate model catalog is unavailable.";
|
|
91
|
+
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "error", error: catalogUnavailable });
|
|
92
|
+
entry.resolve({ action: "error", error: catalogUnavailable });
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
Promise.resolve(ctx.getVendorModelCatalog(ws, vendor)).then(function (catalog) {
|
|
96
|
+
var selected = catalog && catalog.status === "ready" ? selectCatalogModel(catalog.models || [], catalog.defaultModel, "deep") : null;
|
|
97
|
+
if (!selected) throw new Error((catalog && catalog.error) || "No high-capability Mate model is available for " + vendor + ".");
|
|
98
|
+
return ctx.createReadyMate(ws, session.ownerId || null, Object.assign({}, entry.definition, { vendor: vendor, model: selected.value }));
|
|
99
|
+
}).then(function (mate) {
|
|
100
|
+
session.homeMateCreationPhase = "created";
|
|
101
|
+
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "create", mateId: mate.id, mateName: (mate.profile && mate.profile.displayName) || mate.name || "Mate" });
|
|
102
|
+
entry.resolve({ action: "create", mateId: mate.id });
|
|
103
|
+
}).catch(function (error) {
|
|
104
|
+
var text = error && error.message ? error.message : "The Mate could not be created.";
|
|
105
|
+
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "error", error: text });
|
|
106
|
+
entry.resolve({ action: "error", error: text });
|
|
107
|
+
});
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
createMcpServer: createMcpServer,
|
|
113
|
+
getToolDefs: getToolDefs,
|
|
114
|
+
getBridgeTools: getBridgeTools,
|
|
115
|
+
callBridgeTool: callBridgeTool,
|
|
116
|
+
handleHomeMessage: handleHomeMessage,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = { attachMateCreationProposal: attachMateCreationProposal };
|
package/lib/project-memory.js
CHANGED
|
@@ -8,7 +8,8 @@ function attachMemory(ctx) {
|
|
|
8
8
|
var sendTo = ctx.sendTo;
|
|
9
9
|
var matesModule = ctx.matesModule;
|
|
10
10
|
var sessionSearch = ctx.sessionSearch;
|
|
11
|
-
var
|
|
11
|
+
var getWorkspaceMemorySessions = ctx.getWorkspaceMemorySessions || function () { return []; };
|
|
12
|
+
var getOwnedCurrentSessions = ctx.getOwnedCurrentSessions || function () { return []; };
|
|
12
13
|
var projectOwnerId = ctx.projectOwnerId;
|
|
13
14
|
var handleMessage = ctx.handleMessage;
|
|
14
15
|
|
|
@@ -166,7 +167,7 @@ function attachMemory(ctx) {
|
|
|
166
167
|
var timelineEntries = [];
|
|
167
168
|
|
|
168
169
|
// Own sessions
|
|
169
|
-
|
|
170
|
+
getOwnedCurrentSessions().forEach(function (s) {
|
|
170
171
|
if (s.hidden || !s.history || s.history.length === 0) return;
|
|
171
172
|
timelineEntries.push({
|
|
172
173
|
title: s.title || "New Session",
|
|
@@ -176,7 +177,7 @@ function attachMemory(ctx) {
|
|
|
176
177
|
});
|
|
177
178
|
|
|
178
179
|
// Cross-project sessions
|
|
179
|
-
var crossForTimeline =
|
|
180
|
+
var crossForTimeline = getWorkspaceMemorySessions();
|
|
180
181
|
for (var cti = 0; cti < crossForTimeline.length; cti++) {
|
|
181
182
|
var cs = crossForTimeline[cti];
|
|
182
183
|
timelineEntries.push({
|
|
@@ -209,7 +210,7 @@ function attachMemory(ctx) {
|
|
|
209
210
|
try {
|
|
210
211
|
// Collect mate's own sessions
|
|
211
212
|
var mateSessions = [];
|
|
212
|
-
|
|
213
|
+
getOwnedCurrentSessions().forEach(function (s) {
|
|
213
214
|
if (!s.hidden && s.history && s.history.length > 0) {
|
|
214
215
|
mateSessions.push(s);
|
|
215
216
|
}
|
|
@@ -218,7 +219,7 @@ function attachMemory(ctx) {
|
|
|
218
219
|
// globalSearch: also collect sessions from all other projects + knowledge files
|
|
219
220
|
var knowledgeFiles = [];
|
|
220
221
|
if (hasGlobalSearch) {
|
|
221
|
-
var crossSessions =
|
|
222
|
+
var crossSessions = getWorkspaceMemorySessions();
|
|
222
223
|
for (var cs = 0; cs < crossSessions.length; cs++) {
|
|
223
224
|
mateSessions.push(crossSessions[cs]);
|
|
224
225
|
}
|
|
@@ -595,7 +596,7 @@ function attachMemory(ctx) {
|
|
|
595
596
|
|
|
596
597
|
// --- Message handlers for memory management UI ---
|
|
597
598
|
|
|
598
|
-
function
|
|
599
|
+
function readMemoryState() {
|
|
599
600
|
var digestFile = path.join(cwd, "knowledge", "session-digests.jsonl");
|
|
600
601
|
var summaryFile = path.join(cwd, "knowledge", "memory-summary.md");
|
|
601
602
|
var entries = [];
|
|
@@ -620,7 +621,12 @@ function attachMemory(ctx) {
|
|
|
620
621
|
} catch (e) {}
|
|
621
622
|
// Return newest first
|
|
622
623
|
entries.reverse();
|
|
623
|
-
|
|
624
|
+
return { entries: entries, summary: summary };
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function handleMemoryList(ws) {
|
|
628
|
+
var state = readMemoryState();
|
|
629
|
+
sendTo(ws, { type: "memory_list", entries: state.entries, summary: state.summary });
|
|
624
630
|
}
|
|
625
631
|
|
|
626
632
|
function handleMemorySearch(ws, msg) {
|
|
@@ -671,6 +677,7 @@ function attachMemory(ctx) {
|
|
|
671
677
|
gateMemory: gateMemory,
|
|
672
678
|
updateMemorySummary: updateMemorySummary,
|
|
673
679
|
initMemorySummary: initMemorySummary,
|
|
680
|
+
readMemoryState: readMemoryState,
|
|
674
681
|
handleMemoryList: handleMemoryList,
|
|
675
682
|
handleMemorySearch: handleMemorySearch,
|
|
676
683
|
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" },
|