clay-server 5.1.0-beta.1 → 5.1.0-beta.2
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/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon.js +2 -0
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +36 -21
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates.js +18 -0
- package/lib/project-connection.js +36 -2
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-sessions.js +39 -2
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +59 -18
- package/lib/public/app.js +73 -34
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +8 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +151 -0
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +33 -101
- package/lib/public/modules/account-island.js +230 -0
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +34 -9
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +25 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +81 -65
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/profile.js +51 -18
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +4 -1
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +16 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/server-admin.js +11 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +12 -3
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +65 -1
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +21 -1
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +32 -6
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +50 -0
- package/package.json +10 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
|
|
4
|
+
var sequence = 0;
|
|
5
|
+
var timer = null;
|
|
6
|
+
function state() { return store.get('mateInstructionsDraft'); }
|
|
7
|
+
function put(value) { store.set({mateInstructionsDraft: value}); }
|
|
8
|
+
export function resetMateInstructions(mateId) {
|
|
9
|
+
clearTimeout(timer);
|
|
10
|
+
put(mateId ? {mateId: mateId, content: '', saved: '', revision: '', status: 'idle', error: '', requestId: null} : null);
|
|
11
|
+
}
|
|
12
|
+
export function hasMateInstructionDraft() { var s = state(); return !!s && (s.content !== s.saved || s.status === 'saving'); }
|
|
13
|
+
function request(save, render) {
|
|
14
|
+
var s = state();
|
|
15
|
+
if (!s || s.status === 'saving') return;
|
|
16
|
+
var id = 'mate-instructions-' + Date.now() + '-' + (++sequence);
|
|
17
|
+
var ws = getWs();
|
|
18
|
+
if (!ws || ws.readyState !== 1) { put(Object.assign({}, s, {error: 'Clay is offline. Reconnect and try again.', status: s.revision ? 'ready' : 'error'})); render(); return; }
|
|
19
|
+
put(Object.assign({}, s, {requestId: id, status: save ? 'saving' : 'loading', error: ''}));
|
|
20
|
+
render();
|
|
21
|
+
try { ws.send(JSON.stringify({type: save ? 'mate_instructions_set' : 'mate_instructions_get', mateId: s.mateId, requestId: id, content: save ? s.content : undefined, revision: save ? s.revision : undefined})); }
|
|
22
|
+
catch (error) { put(Object.assign({}, state(), {status: s.revision ? 'ready' : 'error', requestId: null, error: 'Could not send. Your draft is retained.'})); render(); return; }
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
timer = setTimeout(function () {
|
|
25
|
+
var current = state();
|
|
26
|
+
if (!current || current.requestId !== id) return;
|
|
27
|
+
put(Object.assign({}, current, {requestId: null, status: current.revision ? 'ready' : 'error', error: 'No response received. Retry to check the saved prompt.'}));
|
|
28
|
+
render();
|
|
29
|
+
}, 15000);
|
|
30
|
+
}
|
|
31
|
+
export function loadMateInstructions(render) { request(false, render); }
|
|
32
|
+
export function applyMateInstructions(msg) {
|
|
33
|
+
var s = state();
|
|
34
|
+
if (!s || msg.mateId !== s.mateId || msg.requestId !== s.requestId) return false;
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
if (!msg.ok) put(Object.assign({}, s, {status: s.revision ? 'ready' : 'error', requestId: null, conflict: !!msg.conflict, error: msg.error || 'Could not save the prompt.'}));
|
|
37
|
+
else put(Object.assign({}, s, {status: 'ready', requestId: null, content: msg.content, saved: msg.content, revision: msg.revision, conflict: false, error: '', notice: msg.operation === 'save' ? 'Prompt saved. New conversations use these instructions.' : ''}));
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
export function renderMateInstructions(body, render) {
|
|
41
|
+
var s = state();
|
|
42
|
+
if (!s) return;
|
|
43
|
+
var section = document.createElement('section');
|
|
44
|
+
section.className = 'mate-instructions';
|
|
45
|
+
section.innerHTML = '<p class="mate-settings-help">The identity and instructions this Mate uses. Clay manages its system capabilities separately.</p>';
|
|
46
|
+
body.appendChild(section);
|
|
47
|
+
if (s.status === 'idle' || (s.status === 'loading' && !s.revision)) {
|
|
48
|
+
section.insertAdjacentHTML('beforeend', '<p role="status" class="mate-settings-help">Loading prompt…</p>');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (s.revision) {
|
|
52
|
+
var input = document.createElement('textarea');
|
|
53
|
+
input.className = 'mate-instructions-input';
|
|
54
|
+
input.id = 'mate-prompt-input';
|
|
55
|
+
input.setAttribute('aria-label', 'Mate prompt');
|
|
56
|
+
input.spellcheck = false;
|
|
57
|
+
input.value = s.content;
|
|
58
|
+
input.disabled = s.status === 'saving' || s.status === 'loading';
|
|
59
|
+
section.appendChild(input);
|
|
60
|
+
input.addEventListener('input', function () { put(Object.assign({}, state(), {content: input.value, notice: ''})); updateActions(); });
|
|
61
|
+
}
|
|
62
|
+
var status = document.createElement('p');
|
|
63
|
+
status.className = 'mate-settings-status' + (s.error ? ' is-error' : '');
|
|
64
|
+
status.setAttribute('role', s.error ? 'alert' : 'status');
|
|
65
|
+
status.textContent = s.error || s.notice || (s.status === 'saving' ? 'Saving prompt…' : '');
|
|
66
|
+
section.appendChild(status);
|
|
67
|
+
var actions = document.createElement('div');
|
|
68
|
+
actions.className = 'mate-settings-savebar';
|
|
69
|
+
section.appendChild(actions);
|
|
70
|
+
function button(text, action, primary) {
|
|
71
|
+
var el = document.createElement('button'); el.type = 'button'; el.textContent = text; el.className = 'mate-settings-button' + (primary ? ' primary' : ''); el.addEventListener('click', action); actions.appendChild(el); return el;
|
|
72
|
+
}
|
|
73
|
+
function updateActions() {
|
|
74
|
+
var current = state(); actions.replaceChildren();
|
|
75
|
+
if (current.conflict || !current.revision) {
|
|
76
|
+
button(current.conflict ? 'Reload saved prompt' : 'Try again', function () { request(false, render); });
|
|
77
|
+
if (current.conflict) {
|
|
78
|
+
var help = document.createElement('span'); help.textContent = 'Copy your draft before reloading.'; help.className = 'mate-settings-help'; actions.appendChild(help);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
actions.hidden = current.content === current.saved && current.status !== 'saving';
|
|
83
|
+
if (actions.hidden) return;
|
|
84
|
+
var cancel = button('Cancel', function () { put(Object.assign({}, current, {content: current.saved, error: '', notice: ''})); render(); });
|
|
85
|
+
var save = button('Save prompt', function () { request(true, render); }, true);
|
|
86
|
+
cancel.disabled = current.status === 'saving';
|
|
87
|
+
save.disabled = current.status === 'saving';
|
|
88
|
+
}
|
|
89
|
+
updateActions();
|
|
90
|
+
}
|
|
@@ -1,281 +1,90 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// Correlated model catalogs and an explicit provider/model draft.
|
|
3
2
|
import { getWs } from './ws-ref.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return entry.displayName || entry.label || entry.name || modelValue(entry) || "Model";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function vendorLabel(vendor) {
|
|
38
|
-
var vendors = state && state.vendors ? state.vendors : [];
|
|
39
|
-
for (var i = 0; i < vendors.length; i++) {
|
|
40
|
-
if (vendors[i] && vendors[i].id === vendor) return vendors[i].displayName || vendor;
|
|
41
|
-
}
|
|
42
|
-
return vendor || "Vendor";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function findFocusTarget(kind, value) {
|
|
46
|
-
if (kind === "retry") return document.querySelector(".home-mate-settings-dialog .home-mate-model-retry");
|
|
47
|
-
if (kind === "selection-status") return document.querySelector(".home-mate-settings-dialog .home-mate-model-selection-status");
|
|
48
|
-
var selector = kind === "vendor" ? ".home-mate-settings-dialog [data-home-mate-vendor]" : ".home-mate-settings-dialog [data-home-mate-model]";
|
|
49
|
-
var datasetKey = kind === "vendor" ? "homeMateVendor" : "homeMateModel";
|
|
50
|
-
var options = document.querySelectorAll(selector);
|
|
51
|
-
for (var i = 0; i < options.length; i++) {
|
|
52
|
-
if (options[i].dataset[datasetKey] === value) return options[i];
|
|
3
|
+
import { store } from './store.js';
|
|
4
|
+
import { enhanceWorkerRuntimePicker } from './worker-runtime-picker.js';
|
|
5
|
+
var sequence = 0;
|
|
6
|
+
var timer = null;
|
|
7
|
+
function state() { return store.get('mateModelDraft'); }
|
|
8
|
+
function put(s) { store.set({mateModelDraft: s}); }
|
|
9
|
+
function value(entry) { return typeof entry === 'string' ? entry : entry.value || entry.id || ''; }
|
|
10
|
+
function label(entry) { return typeof entry === 'string' ? entry : entry.displayName || entry.label || entry.name || value(entry); }
|
|
11
|
+
function send(message) { var ws = getWs(); if (!ws || ws.readyState !== 1) return false; try { ws.send(JSON.stringify(message)); return true; } catch (error) { return false; } }
|
|
12
|
+
function id() { return 'mate-model-' + Date.now() + '-' + (++sequence); }
|
|
13
|
+
export function resetHomeMateModelPicker(mateId, name, mate, sessionId) {
|
|
14
|
+
clearTimeout(timer);
|
|
15
|
+
put({mateId: mateId, name: name, builtinClay: mate.builtinKey === 'clay', sessionId: sessionId || null, vendor: mate.vendor || '', model: mate.model || '', mateVendor: mate.vendor || '', mateModel: mate.model || '', vendors: [], models: [], status: 'idle', requestId: null, saveId: null, error: ''});
|
|
16
|
+
}
|
|
17
|
+
export function clearHomeMateModelPicker() { clearTimeout(timer); put(null); }
|
|
18
|
+
export function hasHomeMateModelDraft() { var s = state(); return !!s && (!!s.saveId || s.vendor !== s.mateVendor || s.model !== s.mateModel); }
|
|
19
|
+
function armTimeout(requestId, render) {
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
timer = setTimeout(function () {
|
|
22
|
+
var s = state(); if (!s || (s.requestId !== requestId && s.saveId !== requestId)) return;
|
|
23
|
+
put(Object.assign({}, s, {requestId: null, saveId: null, status: s.status === 'loading' ? 'error' : s.status, error: 'No response received. Your choices are retained; try again.'})); render();
|
|
24
|
+
}, 15000);
|
|
25
|
+
}
|
|
26
|
+
export function requestHomeMateModels(vendor, render) {
|
|
27
|
+
var s = state(); if (!s || s.saveId) return;
|
|
28
|
+
var requestId = id();
|
|
29
|
+
put(Object.assign({}, s, {vendor: vendor || s.vendor, models: [], status: 'loading', requestId: requestId, error: ''}));
|
|
30
|
+
render();
|
|
31
|
+
if (!send({type: 'home_mate_models_get', mateId: s.mateId, vendor: vendor || s.vendor, requestId: requestId})) {
|
|
32
|
+
put(Object.assign({}, state(), {status: 'error', requestId: null, error: 'Clay is offline. Reconnect and try again.'})); render(); return;
|
|
53
33
|
}
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function clearHomeMateModelPicker() {
|
|
84
|
-
activeMateId = null;
|
|
85
|
-
activeMateName = "Mate";
|
|
86
|
-
state = null;
|
|
87
|
-
requestId = null;
|
|
88
|
-
selectionRequestId = null;
|
|
89
|
-
selectionModel = null;
|
|
90
|
-
activeSessionId = null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function requestHomeMateModels(vendor, rerender, focusAfter) {
|
|
94
|
-
if (!activeMateId || !state || selectionRequestId) return;
|
|
95
|
-
var requestedVendor = vendor || state.vendor || state.mateVendor;
|
|
96
|
-
requestId = nextRequestId("home-mate-models");
|
|
97
|
-
state.vendor = requestedVendor;
|
|
98
|
-
state.status = "loading";
|
|
99
|
-
state.models = [];
|
|
100
|
-
state.error = "";
|
|
101
|
-
rerenderAndFocus(rerender, focusAfter ? "vendor" : "", requestedVendor);
|
|
102
|
-
if (send({ type: "home_mate_models_get", mateId: activeMateId, vendor: requestedVendor, requestId: requestId })) return;
|
|
103
|
-
state.status = "error";
|
|
104
|
-
state.error = "Clay is offline. Reconnect and try again.";
|
|
105
|
-
rerenderAndFocus(rerender, "retry", "");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function selectMateModel(model, rerender) {
|
|
109
|
-
if (!state || selectionRequestId || !model || !state.vendor) return;
|
|
110
|
-
selectionRequestId = nextRequestId("home-mate-model-set");
|
|
111
|
-
selectionModel = model;
|
|
112
|
-
state.error = "";
|
|
113
|
-
rerenderAndFocus(rerender, "selection-status", "");
|
|
114
|
-
var message = { type: "home_mate_model_set", mateId: activeMateId, vendor: state.vendor, model: model, requestId: selectionRequestId };
|
|
115
|
-
if (activeSessionId) message.sessionId = activeSessionId;
|
|
116
|
-
if (send(message)) return;
|
|
117
|
-
selectionRequestId = null;
|
|
118
|
-
selectionModel = null;
|
|
119
|
-
state.error = "Clay is offline. Reconnect and try again.";
|
|
120
|
-
rerenderAndFocus(rerender, "model", model);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function appendHeading(body, text) {
|
|
124
|
-
var heading = document.createElement("h3");
|
|
125
|
-
heading.className = "home-mate-model-section-label";
|
|
126
|
-
heading.textContent = text;
|
|
127
|
-
body.appendChild(heading);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function renderVendors(body, rerender) {
|
|
131
|
-
appendHeading(body, "Vendor");
|
|
132
|
-
var list = document.createElement("div");
|
|
133
|
-
list.className = "home-mate-vendor-list";
|
|
134
|
-
list.setAttribute("role", "group");
|
|
135
|
-
list.setAttribute("aria-label", "Vendor for " + activeMateName);
|
|
136
|
-
var vendors = state.vendors || [];
|
|
137
|
-
for (var i = 0; i < vendors.length; i++) {
|
|
138
|
-
(function (vendor) {
|
|
139
|
-
if (!vendor || !vendor.id) return;
|
|
140
|
-
var button = document.createElement("button");
|
|
141
|
-
button.type = "button";
|
|
142
|
-
button.className = "home-mate-vendor-option";
|
|
143
|
-
button.dataset.homeMateVendor = vendor.id;
|
|
144
|
-
button.textContent = vendor.displayName || vendor.id;
|
|
145
|
-
button.setAttribute("aria-pressed", vendor.id === state.vendor ? "true" : "false");
|
|
146
|
-
button.disabled = !!selectionRequestId;
|
|
147
|
-
if (vendor.id === state.mateVendor) button.title = "Current Mate vendor";
|
|
148
|
-
button.addEventListener("click", function () {
|
|
149
|
-
if (vendor.id !== state.vendor) requestHomeMateModels(vendor.id, rerender, true);
|
|
150
|
-
});
|
|
151
|
-
list.appendChild(button);
|
|
152
|
-
})(vendors[i]);
|
|
153
|
-
}
|
|
154
|
-
if (!vendors.length) {
|
|
155
|
-
var waiting = document.createElement("span");
|
|
156
|
-
waiting.className = "home-mate-model-muted";
|
|
157
|
-
waiting.textContent = "Loading available vendors…";
|
|
158
|
-
list.appendChild(waiting);
|
|
159
|
-
}
|
|
160
|
-
body.appendChild(list);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function appendLoadState(body, rerender) {
|
|
164
|
-
var loadState = document.createElement("div");
|
|
165
|
-
loadState.className = "home-mate-model-state";
|
|
166
|
-
if (state.status === "loading") {
|
|
167
|
-
loadState.classList.add("home-mate-model-loading");
|
|
168
|
-
loadState.setAttribute("role", "status");
|
|
169
|
-
loadState.dataset.homeModelFocus = "catalog-status";
|
|
170
|
-
loadState.tabIndex = -1;
|
|
171
|
-
loadState.textContent = "Loading " + vendorLabel(state.vendor) + " models…";
|
|
172
|
-
} else {
|
|
173
|
-
if (state.status === "error") loadState.setAttribute("role", "alert");
|
|
174
|
-
loadState.textContent = state.error || "No models are available for this vendor.";
|
|
175
|
-
var retry = document.createElement("button");
|
|
176
|
-
retry.type = "button";
|
|
177
|
-
retry.className = "home-mate-model-retry";
|
|
178
|
-
retry.dataset.homeModelFocus = "catalog-status";
|
|
179
|
-
retry.textContent = "Try again";
|
|
180
|
-
retry.addEventListener("click", function () { requestHomeMateModels(state.vendor, rerender, false); });
|
|
181
|
-
loadState.appendChild(retry);
|
|
182
|
-
}
|
|
183
|
-
body.appendChild(loadState);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function renderModels(body, rerender) {
|
|
187
|
-
appendHeading(body, "Model");
|
|
188
|
-
if (state.status !== "ready") {
|
|
189
|
-
appendLoadState(body, rerender);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
var list = document.createElement("div");
|
|
193
|
-
list.className = "home-mate-model-list";
|
|
194
|
-
list.setAttribute("role", "group");
|
|
195
|
-
list.setAttribute("aria-label", "Models from " + vendorLabel(state.vendor) + " for " + activeMateName);
|
|
196
|
-
var models = state.models || [];
|
|
197
|
-
for (var i = 0; i < models.length; i++) {
|
|
198
|
-
(function (entry) {
|
|
199
|
-
var value = modelValue(entry);
|
|
200
|
-
if (!value) return;
|
|
201
|
-
var button = document.createElement("button");
|
|
202
|
-
button.type = "button";
|
|
203
|
-
button.className = "home-mate-model-option";
|
|
204
|
-
button.dataset.homeMateModel = value;
|
|
205
|
-
button.setAttribute("aria-pressed", state.vendor === state.mateVendor && value === state.mateModel ? "true" : "false");
|
|
206
|
-
button.disabled = !!selectionRequestId;
|
|
207
|
-
var label = document.createElement("span");
|
|
208
|
-
label.textContent = modelLabel(entry);
|
|
209
|
-
var id = document.createElement("small");
|
|
210
|
-
id.textContent = value;
|
|
211
|
-
button.appendChild(label);
|
|
212
|
-
button.appendChild(id);
|
|
213
|
-
button.addEventListener("click", function () { selectMateModel(value, rerender); });
|
|
214
|
-
list.appendChild(button);
|
|
215
|
-
})(models[i]);
|
|
216
|
-
}
|
|
217
|
-
body.appendChild(list);
|
|
218
|
-
var status = document.createElement("div");
|
|
219
|
-
status.className = "home-mate-model-selection-status";
|
|
220
|
-
status.setAttribute("aria-live", "polite");
|
|
221
|
-
if (selectionRequestId) {
|
|
222
|
-
status.dataset.homeMateModel = selectionModel;
|
|
223
|
-
status.tabIndex = -1;
|
|
224
|
-
}
|
|
225
|
-
status.textContent = selectionRequestId ? "Saving vendor and model…" : (state.error || "");
|
|
226
|
-
body.appendChild(status);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export function renderHomeMateModelPicker(body, rerender) {
|
|
230
|
-
var note = document.createElement("p");
|
|
231
|
-
note.className = "home-mate-model-note";
|
|
232
|
-
note.textContent = activeSessionId ? "Used for this draft and future new conversations. Conversations with activity keep their committed vendor and model." : "Used for new conversations. Existing conversations keep their current vendor and model.";
|
|
34
|
+
armTimeout(requestId, render);
|
|
35
|
+
}
|
|
36
|
+
function save(render) {
|
|
37
|
+
var s = state(); if (!s || s.saveId || s.status !== 'ready' || !s.models.some(function (m) { return value(m) === s.model; })) return;
|
|
38
|
+
var saveId = id(); put(Object.assign({}, s, {saveId: saveId, error: '', notice: ''})); render();
|
|
39
|
+
var message = {type:'home_mate_model_set', mateId:s.mateId, vendor:s.vendor, model:s.model, requestId:saveId};
|
|
40
|
+
if (s.sessionId) message.sessionId = s.sessionId;
|
|
41
|
+
if (!send(message)) { put(Object.assign({}, state(), {saveId:null, error:'Clay is offline. Your choices are retained.'})); render(); return; }
|
|
42
|
+
armTimeout(saveId, render);
|
|
43
|
+
}
|
|
44
|
+
function selector(body, title, help, entries, selected, disabled, onChange) {
|
|
45
|
+
var row = document.createElement('div'); row.className = 'mate-settings-row';
|
|
46
|
+
var text = document.createElement('div'); var heading = document.createElement('label'); heading.textContent = title;
|
|
47
|
+
var hint = document.createElement('p'); hint.textContent = help; text.appendChild(heading); text.appendChild(hint); row.appendChild(text);
|
|
48
|
+
var control = document.createElement('div'); control.className = 'mate-settings-value';
|
|
49
|
+
var select = document.createElement('select'); select.className = 'worker-proposal-select'; select.setAttribute('aria-label', title); select.id = 'mate-settings-' + title.toLowerCase(); heading.htmlFor = select.id;
|
|
50
|
+
if (!entries.some(function (e) { return value(e) === selected; })) { var empty = document.createElement('option'); empty.value = selected; empty.textContent = selected || 'Choose a model'; empty.disabled = true; select.appendChild(empty); }
|
|
51
|
+
entries.forEach(function (entry) { var option = document.createElement('option'); option.value = value(entry); option.textContent = label(entry); select.appendChild(option); });
|
|
52
|
+
select.value = selected; select.disabled = disabled; select.addEventListener('change', function () { onChange(select.value); });
|
|
53
|
+
control.appendChild(select); row.appendChild(control); body.appendChild(row);
|
|
54
|
+
enhanceWorkerRuntimePicker(select, title, body.closest('.home-mate-settings-dialog'));
|
|
55
|
+
}
|
|
56
|
+
export function renderHomeMateModelPicker(body, render) {
|
|
57
|
+
var s = state(); if (!s) return;
|
|
58
|
+
var note = document.createElement('p'); note.className = 'mate-settings-help';
|
|
59
|
+
note.textContent = s.sessionId ? 'Used for this draft and future conversations. Conversations with activity keep their committed model.' : 'Used for new conversations with this Mate. Existing conversations keep their current model.';
|
|
60
|
+
if (s.builtinClay) note.textContent = 'Clay uses your Default AI for new conversations. This choice can update an eligible current draft; conversations with activity keep their committed model.';
|
|
233
61
|
body.appendChild(note);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
62
|
+
selector(body, 'Provider', 'Choose the service for this Mate.', s.vendors.map(function (v) { return {value:v.id, displayName:v.displayName || v.id}; }), s.vendor, !!s.saveId || !s.vendors.length, function (vendor) {
|
|
63
|
+
put(Object.assign({}, state(), {vendor:vendor, model:vendor === s.mateVendor ? s.mateModel : '', notice:''})); requestHomeMateModels(vendor, render);
|
|
64
|
+
});
|
|
65
|
+
selector(body, 'Model', 'Available models come from the selected provider.', s.models, s.model, !!s.saveId || s.status !== 'ready', function (model) { put(Object.assign({}, state(), {model:model, error:'', notice:''})); render(); });
|
|
66
|
+
var status = document.createElement('p'); status.className = 'mate-settings-status' + (s.error ? ' is-error' : ''); status.setAttribute('role', s.error ? 'alert' : 'status');
|
|
67
|
+
status.textContent = s.saveId ? 'Saving provider and model…' : s.status === 'loading' ? 'Loading models…' : s.error || s.notice || (s.status === 'empty' ? 'No models are available from this provider.' : ''); body.appendChild(status);
|
|
68
|
+
if (s.status === 'error' || s.status === 'empty') { var retry = document.createElement('button'); retry.type = 'button'; retry.className = 'mate-settings-button home-mate-model-retry'; retry.textContent = 'Try again'; retry.addEventListener('click', function () { requestHomeMateModels(s.vendor, render); }); body.appendChild(retry); }
|
|
69
|
+
if (!hasHomeMateModelDraft()) return;
|
|
70
|
+
var bar = document.createElement('div'); bar.className = 'mate-settings-savebar';
|
|
71
|
+
var cancel = document.createElement('button'); cancel.type = 'button'; cancel.className = 'mate-settings-button'; cancel.textContent = 'Cancel'; cancel.disabled = !!s.saveId;
|
|
72
|
+
cancel.addEventListener('click', function () { put(Object.assign({}, state(), {vendor:s.mateVendor, model:s.mateModel, error:'', notice:''})); requestHomeMateModels(s.mateVendor, render); });
|
|
73
|
+
var apply = document.createElement('button'); apply.type = 'button'; apply.className = 'mate-settings-button primary'; apply.textContent = 'Save model'; apply.disabled = !!s.saveId || s.status !== 'ready' || !s.models.some(function (m) { return value(m) === s.model; }); apply.addEventListener('click', function () { save(render); });
|
|
74
|
+
bar.appendChild(cancel); bar.appendChild(apply); body.appendChild(bar);
|
|
243
75
|
}
|
|
244
|
-
|
|
245
76
|
export function applyHomeMateModelsState(msg) {
|
|
246
|
-
if (!
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
state.model = msg.model || "";
|
|
250
|
-
state.mateVendor = msg.mateVendor || state.mateVendor;
|
|
251
|
-
state.mateModel = msg.mateModel || state.mateModel;
|
|
252
|
-
state.vendors = Array.isArray(msg.vendors) ? msg.vendors : state.vendors;
|
|
253
|
-
state.models = Array.isArray(msg.models) ? msg.models : [];
|
|
254
|
-
state.error = msg.error || "";
|
|
77
|
+
var s = state(); if (!s || msg.mateId !== s.mateId || msg.requestId !== s.requestId) return false;
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
put(Object.assign({}, s, {requestId:null, status:msg.status || 'empty', vendor:msg.vendor || s.vendor, model:s.model || msg.model || '', mateVendor:msg.mateVendor || s.mateVendor, mateModel:msg.mateModel || s.mateModel, vendors:msg.vendors || s.vendors, models:msg.models || [], error:msg.error || ''}));
|
|
255
80
|
return true;
|
|
256
81
|
}
|
|
257
|
-
|
|
258
82
|
export function applyHomeMateModelResult(msg) {
|
|
259
|
-
if (!
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
state.mateVendor = msg.vendor || state.vendor;
|
|
267
|
-
state.mateModel = msg.model || state.model;
|
|
268
|
-
state.model = state.mateModel;
|
|
269
|
-
state.error = msg.requestedSessionId && !msg.sessionApplied ? (msg.sessionReason || "Mate default updated. This conversation keeps its committed model.") : "";
|
|
270
|
-
window.dispatchEvent(new CustomEvent("clay:home-mate-model-confirmed", { detail: {
|
|
271
|
-
mateId: msg.mateId,
|
|
272
|
-
vendor: state.mateVendor,
|
|
273
|
-
model: state.mateModel,
|
|
274
|
-
requestedSessionId: msg.requestedSessionId || null,
|
|
275
|
-
sessionId: msg.sessionId || null,
|
|
276
|
-
sessionApplied: msg.sessionApplied === true,
|
|
277
|
-
sessionVendor: msg.sessionVendor || null,
|
|
278
|
-
sessionModel: msg.sessionModel || null,
|
|
279
|
-
} }));
|
|
83
|
+
var s = state(); if (!s || msg.mateId !== s.mateId || msg.requestId !== s.saveId) return false;
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
if (!msg.ok) { put(Object.assign({}, s, {saveId:null, error:msg.error || 'Could not save. Your choices are retained.'})); return true; }
|
|
86
|
+
var vendor = msg.vendor || s.vendor; var model = msg.model || s.model;
|
|
87
|
+
put(Object.assign({}, s, {saveId:null, vendor:vendor, model:model, mateVendor:vendor, mateModel:model, error:'', notice:msg.requestedSessionId && !msg.sessionApplied ? (msg.sessionReason || 'Default saved. This conversation keeps its committed model.') : 'Model saved.'}));
|
|
88
|
+
window.dispatchEvent(new CustomEvent('clay:home-mate-model-confirmed', {detail:{mateId:msg.mateId, vendor:vendor, model:model, requestedSessionId:msg.requestedSessionId || null, sessionId:msg.sessionId || null, sessionApplied:msg.sessionApplied === true, sessionVendor:msg.sessionVendor || null, sessionModel:msg.sessionModel || null}}));
|
|
280
89
|
return true;
|
|
281
90
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { mateAvatarUrl } from './avatar.js';
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import { getWs } from './ws-ref.js';
|
|
4
|
+
var timer = null;
|
|
5
|
+
var sequence = 0;
|
|
6
|
+
function state() { return store.get('mateProfileDraft'); }
|
|
7
|
+
function put(s) { store.set({mateProfileDraft:s}); }
|
|
8
|
+
function name(mate) { return (mate.profile || {}).displayName || mate.name || 'Mate'; }
|
|
9
|
+
export function resetMateProfile() { clearTimeout(timer); put(null); }
|
|
10
|
+
export function hasMateProfileDraft() { var s = state(); return !!s && (!!s.requestId || s.name !== s.savedName || s.bio !== s.savedBio); }
|
|
11
|
+
export function mateProfileSaving() { var s = state(); return !!s && !!s.requestId; }
|
|
12
|
+
export function applyMateProfile(msg) {
|
|
13
|
+
var s = state();
|
|
14
|
+
if (!s || !s.requestId || msg.requestId !== s.requestId || (msg.mate ? msg.mate.id : msg.mateId) !== s.mateId) return false;
|
|
15
|
+
clearTimeout(timer);
|
|
16
|
+
if (msg.mate) put(null);
|
|
17
|
+
else put(Object.assign({},s,{requestId:null,error:msg.error || 'Could not save. Your changes are retained.'}));
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
export function renderMateProfile(body, mate, render, editAvatar) {
|
|
21
|
+
var section = document.createElement('section'); section.className = 'mate-settings-profile';
|
|
22
|
+
var heading = document.createElement('div'); heading.className = 'mate-settings-profile-heading';
|
|
23
|
+
var title = document.createElement('h4'); title.textContent = name(mate); heading.appendChild(title);
|
|
24
|
+
var avatar = document.createElement('button'); avatar.type = 'button'; avatar.className = 'mate-settings-profile-avatar';
|
|
25
|
+
avatar.id = 'mate-profile-avatar'; avatar.setAttribute('aria-label','Change Mate avatar'); avatar.title = 'Change avatar';
|
|
26
|
+
avatar.disabled = !!(mate.profile || {}).avatarLocked;
|
|
27
|
+
avatar.setAttribute('aria-expanded',String(!!store.get('mateSettingsAvatarOpen')));
|
|
28
|
+
var image = document.createElement('img'); image.src = mateAvatarUrl(mate,72); image.alt = ''; avatar.appendChild(image);
|
|
29
|
+
avatar.addEventListener('click',editAvatar); section.appendChild(avatar);
|
|
30
|
+
section.appendChild(heading); body.appendChild(section);
|
|
31
|
+
var s = state();
|
|
32
|
+
function button(label, action, primary, parent) {
|
|
33
|
+
var b = document.createElement('button'); b.type = 'button'; b.textContent = label;
|
|
34
|
+
b.className = 'mate-settings-button' + (primary ? ' primary' : ''); b.disabled = !!s && !!s.requestId;
|
|
35
|
+
b.addEventListener('click',action); (parent || section).appendChild(b); return b;
|
|
36
|
+
}
|
|
37
|
+
if (!s || s.mateId !== mate.id) {
|
|
38
|
+
if (!mate.primary) {
|
|
39
|
+
var edit = button('Edit',function () {
|
|
40
|
+
put({mateId:mate.id,name:name(mate),bio:mate.bio || '',savedName:name(mate),savedBio:mate.bio || '',error:'',requestId:null});
|
|
41
|
+
render(); document.getElementById('mate-profile-name').focus();
|
|
42
|
+
},false,heading); edit.id = 'mate-profile-edit'; edit.setAttribute('aria-label','Edit Mate identity');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var bio = document.createElement('p'); bio.className = 'mate-settings-help'; bio.textContent = mate.bio || 'No introduction yet.'; section.appendChild(bio);
|
|
46
|
+
if (mate.primary) { var note = document.createElement('p'); note.className = 'mate-settings-help'; note.textContent = 'Clay manages this built-in identity.'; section.appendChild(note); }
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
section.classList.add('is-editing');
|
|
50
|
+
function field(title, key, multiline) {
|
|
51
|
+
var label = document.createElement('label'); label.className = 'mate-settings-profile-field'; label.textContent = title;
|
|
52
|
+
var input = document.createElement(multiline ? 'textarea' : 'input'); input.id = 'mate-profile-' + key; input.value = s[key]; input.disabled = !!s.requestId;
|
|
53
|
+
input.addEventListener('input',function () { put(Object.assign({},state(),{[key]:input.value})); });
|
|
54
|
+
label.appendChild(input); section.appendChild(label);
|
|
55
|
+
}
|
|
56
|
+
field('Name','name',false); field('Introduction','bio',true);
|
|
57
|
+
var status = document.createElement('p'); status.className = 'mate-settings-status' + (s.error ? ' is-error' : ''); status.setAttribute('role',s.error ? 'alert' : 'status'); status.textContent = s.error || (s.requestId ? 'Saving identity…' : ''); section.appendChild(status);
|
|
58
|
+
var bar = document.createElement('div'); bar.className = 'mate-settings-savebar'; section.appendChild(bar);
|
|
59
|
+
button('Cancel',function () { resetMateProfile(); render(); document.getElementById('mate-profile-edit').focus(); },false,bar);
|
|
60
|
+
button('Save identity',function () {
|
|
61
|
+
var draft = state(); var ws = getWs();
|
|
62
|
+
if (!draft.name.trim()) { put(Object.assign({},draft,{error:'Enter a name.'})); render(); return; }
|
|
63
|
+
if (!ws || ws.readyState !== 1) { put(Object.assign({},draft,{error:'Clay is offline. Your changes are retained.'})); render(); return; }
|
|
64
|
+
var requestId = 'mate-profile-' + Date.now() + '-' + (++sequence);
|
|
65
|
+
put(Object.assign({},draft,{requestId:requestId,error:''})); render();
|
|
66
|
+
try {
|
|
67
|
+
var latest = (store.get('cachedMatesList') || []).find(function (m) { return m.id === mate.id; }) || mate;
|
|
68
|
+
ws.send(JSON.stringify({type:'mate_update',mateId:mate.id,requestId:requestId,updates:{name:draft.name.trim(),bio:draft.bio.trim(),profile:Object.assign({},latest.profile,{displayName:draft.name.trim()})}}));
|
|
69
|
+
} catch (error) { put(Object.assign({},draft,{requestId:null,error:'Could not send. Your changes are retained.'})); render(); return; }
|
|
70
|
+
clearTimeout(timer); timer = setTimeout(function () { if (state() && state().requestId === requestId) { put(Object.assign({},state(),{requestId:null,error:'No response received. Your changes are retained; try again.'})); render(); } },15000);
|
|
71
|
+
},true,bar);
|
|
72
|
+
}
|