clay-server 5.1.0-beta.1 → 5.1.0-beta.3
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/bin/cli.js +9 -91
- package/lib/builtin-mates.js +7 -7
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon-settings.js +11 -0
- package/lib/daemon.js +10 -37
- 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/linear-store.js +35 -8
- package/lib/mate-identity-file.js +39 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +37 -22
- package/lib/mate-ready-creation.js +2 -1
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates-identity.js +4 -4
- package/lib/mates-prompts.js +4 -3
- package/lib/mates.js +30 -11
- package/lib/os-users.js +5 -16
- package/lib/project-connection.js +36 -9
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +4 -2
- package/lib/project-filesystem.js +21 -39
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-mate-interaction.js +7 -6
- package/lib/project-server-settings.js +31 -0
- package/lib/project-sessions.js +92 -182
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +62 -21
- package/lib/public/app.js +79 -71
- 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/input.css +3 -1
- 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/menus.css +3 -0
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +15 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/project-settings-modal.css +56 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/server-settings-system.css +125 -0
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/session-github.css +25 -16
- package/lib/public/css/settings-ui.css +247 -22
- package/lib/public/css/shared-browser.css +7 -3
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +156 -1
- 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 +206 -548
- package/lib/public/modules/account-island.js +232 -0
- package/lib/public/modules/admin-settings-email.js +197 -0
- package/lib/public/modules/admin-settings-invitations.js +183 -0
- package/lib/public/modules/admin-settings-projects.js +198 -0
- package/lib/public/modules/admin-settings-ui.js +100 -0
- package/lib/public/modules/admin-settings-users.js +331 -0
- package/lib/public/modules/admin.js +19 -949
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-dm.js +0 -2
- 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 +47 -61
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rate-limit.js +70 -12
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +30 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/context-sources.js +27 -18
- 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 +88 -65
- package/lib/public/modules/header-tui-font.js +10 -20
- 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/linear-settings.js +3 -2
- package/lib/public/modules/markdown.js +5 -6
- 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/notification-settings.js +81 -0
- package/lib/public/modules/notifications.js +44 -28
- package/lib/public/modules/personal-settings-dialog.js +51 -0
- package/lib/public/modules/profile.js +66 -24
- 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-settings-environment.js +106 -0
- package/lib/public/modules/project-settings.js +72 -628
- 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/server-settings-controls.js +316 -0
- package/lib/public/modules/server-settings-environment.js +194 -0
- package/lib/public/modules/server-settings-navigation.js +39 -0
- package/lib/public/modules/server-settings-state.js +54 -0
- package/lib/public/modules/server-settings.js +116 -788
- package/lib/public/modules/server-storage-settings.js +84 -0
- 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-github.js +2 -1
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +3 -0
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/settings-env-values.js +34 -0
- package/lib/public/modules/settings-select.js +121 -0
- package/lib/public/modules/shared-browser.js +22 -12
- 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/stt-picker.js +14 -5
- package/lib/public/modules/terminal-prefs.js +22 -0
- package/lib/public/modules/theme.js +88 -52
- 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/user-settings-account.js +318 -0
- package/lib/public/modules/user-settings-appearance.js +55 -0
- package/lib/public/modules/user-settings-editors.js +24 -0
- package/lib/public/modules/user-settings-integrations.js +104 -0
- package/lib/public/modules/user-settings-layout.js +80 -0
- package/lib/public/modules/user-settings-preferences.js +48 -0
- package/lib/public/modules/user-settings-profile.js +53 -0
- package/lib/public/modules/user-settings-themes.js +38 -0
- package/lib/public/modules/user-settings-voice.js +75 -0
- package/lib/public/modules/user-settings.js +53 -480
- 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 +20 -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/sdk-message-processor.js +16 -4
- package/lib/sdk-quota-snapshot.js +37 -0
- package/lib/server-admin.js +11 -0
- package/lib/server-appearance-settings.js +71 -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-linear.js +14 -8
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +14 -4
- package/lib/server-notification-settings.js +67 -0
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +69 -1
- package/lib/server-storage.js +57 -0
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +31 -3
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +35 -10
- package/lib/startup-projects.js +40 -0
- package/lib/storage-native-walk.js +85 -0
- package/lib/storage-usage.js +144 -0
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-preferences.js +0 -74
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -4
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +52 -4
- package/lib/yoke/acp-process-manager.js +2 -2
- package/lib/yoke/adapters/codex.js +12 -52
- package/lib/yoke/codex-app-server.js +2 -2
- package/lib/yoke/codex-model-catalog.js +52 -0
- package/lib/yoke/codex-rate-limits.js +26 -0
- package/package.json +12 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setChatLayout } from './theme.js';
|
|
1
2
|
// User profile module — profile popovers for people and Mates
|
|
2
3
|
// Stores profile server-side in ~/.clay/profile.json
|
|
3
4
|
// Generated identities use deterministic local pixel identicons.
|
|
@@ -7,7 +8,6 @@ import { avatarUrl, mateAvatarUrl, mateMarkUrl, userAvatarSeed } from './avatar.
|
|
|
7
8
|
import { store } from './store.js';
|
|
8
9
|
import { applyTerminalFont } from './terminal-prefs.js';
|
|
9
10
|
|
|
10
|
-
var ctx;
|
|
11
11
|
var profile = { name: '', lang: 'en-US', avatarStyle: 'imprint', avatarSeed: '', avatarColor: '#5857fc', avatarCustom: '' };
|
|
12
12
|
var profileUsername = '';
|
|
13
13
|
var popoverEl = null;
|
|
@@ -84,6 +84,54 @@ export function applyToIsland() {
|
|
|
84
84
|
ctaEl.classList.add('hidden');
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
document.dispatchEvent(new CustomEvent('clay:profile-updated'));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function saveProfileUpdates(updates) {
|
|
91
|
+
var next = Object.assign({}, profile, updates);
|
|
92
|
+
var response = await fetch('/api/profile', {method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(next)});
|
|
93
|
+
var result = await response.json();
|
|
94
|
+
if (!response.ok || result.error) throw new Error(result.error || 'Could not save your profile. Your draft is retained.');
|
|
95
|
+
profile = next;
|
|
96
|
+
applyToIsland();
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function updateProfileName(name) {
|
|
101
|
+
profile.name = String(name || '').trim();
|
|
102
|
+
applyToIsland();
|
|
103
|
+
debouncedSave();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function usePixelAvatar() {
|
|
107
|
+
profile.avatarCustom = '';
|
|
108
|
+
applyToIsland();
|
|
109
|
+
debouncedSave();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function regenerateProfileAvatar() {
|
|
113
|
+
profile.avatarCustom = '';
|
|
114
|
+
profile.avatarSeed = 'clay-' + Date.now();
|
|
115
|
+
applyToIsland();
|
|
116
|
+
debouncedSave();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function uploadAvatarBlob(blob) {
|
|
120
|
+
if (!blob) return Promise.reject(new Error('Missing avatar image.'));
|
|
121
|
+
return blob.arrayBuffer().then(function(ab) {
|
|
122
|
+
var buf = new Uint8Array(ab);
|
|
123
|
+
return fetch('/api/avatar', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: { 'Content-Type': 'application/octet-stream' },
|
|
126
|
+
body: buf,
|
|
127
|
+
});
|
|
128
|
+
}).then(function(r) { return r.json(); }).then(function(data) {
|
|
129
|
+
if (!data.ok || !data.avatar) throw new Error(data.error || 'Avatar upload failed.');
|
|
130
|
+
profile.avatarCustom = data.avatar;
|
|
131
|
+
applyToIsland();
|
|
132
|
+
debouncedSave();
|
|
133
|
+
return data;
|
|
134
|
+
});
|
|
87
135
|
}
|
|
88
136
|
|
|
89
137
|
// --- Avatar position picker ---
|
|
@@ -128,6 +176,8 @@ export function showAvatarPositioner(img, objectUrl, onDone) {
|
|
|
128
176
|
|
|
129
177
|
var closeBtn = document.createElement('button');
|
|
130
178
|
closeBtn.className = 'avatar-positioner-close';
|
|
179
|
+
closeBtn.type = 'button';
|
|
180
|
+
closeBtn.setAttribute('aria-label', 'Close avatar crop editor');
|
|
131
181
|
closeBtn.innerHTML = '×';
|
|
132
182
|
container.appendChild(closeBtn);
|
|
133
183
|
|
|
@@ -239,12 +289,21 @@ export function showAvatarPositioner(img, objectUrl, onDone) {
|
|
|
239
289
|
}, { passive: false });
|
|
240
290
|
|
|
241
291
|
function cleanup(revoke) {
|
|
292
|
+
document.removeEventListener('keydown', onOverlayKeydown);
|
|
242
293
|
overlay.remove();
|
|
243
294
|
if (revoke) URL.revokeObjectURL(objectUrl);
|
|
244
295
|
}
|
|
245
296
|
|
|
297
|
+
function onOverlayKeydown(event) {
|
|
298
|
+
if (event.key !== 'Escape') return;
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
event.stopPropagation();
|
|
301
|
+
cleanup(true);
|
|
302
|
+
}
|
|
303
|
+
|
|
246
304
|
closeBtn.addEventListener('click', function() { cleanup(true); });
|
|
247
305
|
cancelBtn.addEventListener('click', function() { cleanup(true); });
|
|
306
|
+
document.addEventListener('keydown', onOverlayKeydown);
|
|
248
307
|
|
|
249
308
|
doneBtn.addEventListener('click', function() {
|
|
250
309
|
// Render cropped area to canvas
|
|
@@ -269,7 +328,7 @@ export function showAvatarPositioner(img, objectUrl, onDone) {
|
|
|
269
328
|
}
|
|
270
329
|
|
|
271
330
|
// --- Popover ---
|
|
272
|
-
function
|
|
331
|
+
export function openProfileEditor() {
|
|
273
332
|
if (popoverEl) {
|
|
274
333
|
hidePopover();
|
|
275
334
|
return;
|
|
@@ -286,7 +345,7 @@ function showPopover() {
|
|
|
286
345
|
|
|
287
346
|
// Banner + close
|
|
288
347
|
html += '<div class="profile-banner">';
|
|
289
|
-
html += '<button class="profile-close-btn">×</button>';
|
|
348
|
+
html += '<button class="profile-close-btn" type="button" aria-label="Close profile editor">×</button>';
|
|
290
349
|
html += '</div>';
|
|
291
350
|
|
|
292
351
|
// Avatar row (overlapping banner)
|
|
@@ -479,28 +538,11 @@ function escapeAttr(str) {
|
|
|
479
538
|
}
|
|
480
539
|
|
|
481
540
|
// --- Init ---
|
|
482
|
-
export function initProfile(
|
|
483
|
-
ctx = _ctx;
|
|
541
|
+
export function initProfile() {
|
|
484
542
|
|
|
485
543
|
var island = document.getElementById('user-island');
|
|
486
544
|
if (!island) return;
|
|
487
545
|
|
|
488
|
-
var profileArea = island.querySelector('.user-island-profile');
|
|
489
|
-
if (profileArea) {
|
|
490
|
-
profileArea.addEventListener('click', function(e) {
|
|
491
|
-
e.stopPropagation();
|
|
492
|
-
showPopover();
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
var ctaEl = island.querySelector('.user-island-cta');
|
|
497
|
-
if (ctaEl) {
|
|
498
|
-
ctaEl.addEventListener('click', function(e) {
|
|
499
|
-
e.stopPropagation();
|
|
500
|
-
showPopover();
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
546
|
fetchProfile().then(function(data) {
|
|
505
547
|
if (data.name !== undefined) profile.name = data.name;
|
|
506
548
|
if (data.lang) profile.lang = data.lang;
|
|
@@ -523,13 +565,13 @@ export function initProfile(_ctx) {
|
|
|
523
565
|
// when the user opened the Settings modal (user-settings.js's
|
|
524
566
|
// populateAccount), so a hard refresh would drop persisted picks back
|
|
525
567
|
// to defaults until the modal was visited.
|
|
568
|
+
if(data.chatLayout)setChatLayout(data.chatLayout);
|
|
526
569
|
if (data.terminalFont && typeof data.terminalFont === "object") {
|
|
527
570
|
applyTerminalFont(data.terminalFont.family, data.terminalFont.size);
|
|
528
571
|
}
|
|
529
572
|
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
var matesOn = data.matesEnabled === true;
|
|
573
|
+
// Keep project Mate DM shortcuts available for legacy profiles too.
|
|
574
|
+
var matesOn = true;
|
|
533
575
|
store.set({ projectMateDmsEnabled: matesOn });
|
|
534
576
|
if (document.body) document.body.classList.toggle('project-mate-dms-disabled', !matesOn);
|
|
535
577
|
}).catch(function(err) {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Session-bound assistant identity for ordinary project and Mate transcripts.
|
|
2
|
+
|
|
3
|
+
import { store } from './store.js';
|
|
4
|
+
import { mateAvatarUrl } from './avatar.js';
|
|
5
|
+
import { VENDOR_AVATARS, VENDOR_NAMES } from './chat-render-runtime.js';
|
|
6
|
+
|
|
7
|
+
function mateById(state, mateId) {
|
|
8
|
+
var mates = state.cachedMatesList || [];
|
|
9
|
+
for (var i = 0; i < mates.length; i++) {
|
|
10
|
+
if (mates[i] && mates[i].id === mateId) return mates[i];
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function mateName(mate, fallback) {
|
|
16
|
+
var profile = mate && mate.profile ? mate.profile : {};
|
|
17
|
+
return profile.displayName || (mate && (mate.displayName || mate.name)) || fallback || 'Mate';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function resolveProjectAssistantIdentity(state, vendor) {
|
|
21
|
+
state = state || store.snap();
|
|
22
|
+
var dmTarget = state.dmMode && state.dmTargetUser && state.dmTargetUser.isMate ? state.dmTargetUser : null;
|
|
23
|
+
var mateId = dmTarget ? dmTarget.id : state.activeSessionMateId;
|
|
24
|
+
if (mateId) {
|
|
25
|
+
var mate = mateById(state, mateId) || dmTarget;
|
|
26
|
+
var fallbackName = dmTarget && dmTarget.displayName || state.activeSessionMateName || 'Mate';
|
|
27
|
+
var avatarMate = mate || { id: mateId, name: fallbackName, profile: { displayName: fallbackName } };
|
|
28
|
+
return {
|
|
29
|
+
kind: 'mate',
|
|
30
|
+
mateId: mateId,
|
|
31
|
+
name: mateName(mate, fallbackName),
|
|
32
|
+
avatarUrl: mateAvatarUrl(avatarMate, 34),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
var vendorId = vendor || state.currentVendor || 'claude';
|
|
36
|
+
return {
|
|
37
|
+
kind: 'provider',
|
|
38
|
+
mateId: '',
|
|
39
|
+
name: VENDOR_NAMES[vendorId] || VENDOR_NAMES.claude,
|
|
40
|
+
avatarUrl: VENDOR_AVATARS[vendorId] || VENDOR_AVATARS.claude,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getProjectAssistantPlaceholder(state, vendor) {
|
|
45
|
+
return 'Message ' + resolveProjectAssistantIdentity(state, vendor).name + '...';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function applyProjectAssistantIdentity(element, identity) {
|
|
49
|
+
if (!element || !identity) return element;
|
|
50
|
+
var avatar = element.querySelector('.dm-bubble-avatar');
|
|
51
|
+
var name = element.querySelector('.dm-bubble-name');
|
|
52
|
+
if (avatar) avatar.src = identity.avatarUrl;
|
|
53
|
+
if (name) name.textContent = identity.name;
|
|
54
|
+
if (identity.kind === 'mate') {
|
|
55
|
+
element.dataset.sessionMateId = identity.mateId;
|
|
56
|
+
element.dataset.sessionMateName = identity.name;
|
|
57
|
+
} else {
|
|
58
|
+
delete element.dataset.sessionMateId;
|
|
59
|
+
delete element.dataset.sessionMateName;
|
|
60
|
+
}
|
|
61
|
+
return element;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function refreshProjectAssistantIdentities(root) {
|
|
65
|
+
var target = root || document;
|
|
66
|
+
var elements = target.querySelectorAll('[data-session-mate-id]');
|
|
67
|
+
var state = store.snap();
|
|
68
|
+
for (var i = 0; i < elements.length; i++) {
|
|
69
|
+
var mateId = elements[i].dataset.sessionMateId;
|
|
70
|
+
var mate = mateById(state, mateId);
|
|
71
|
+
if (!mate) continue;
|
|
72
|
+
applyProjectAssistantIdentity(elements[i], {
|
|
73
|
+
kind: 'mate',
|
|
74
|
+
mateId: mateId,
|
|
75
|
+
name: mateName(mate, elements[i].dataset.sessionMateName || 'Mate'),
|
|
76
|
+
avatarUrl: mateAvatarUrl(mate, 34),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// Project-chat adapter for Clay's existing server-owned debate setup flow.
|
|
2
|
+
|
|
3
|
+
import { store } from './store.js';
|
|
4
|
+
import { getWs } from './ws-ref.js';
|
|
5
|
+
import { addToMessages, scrollToBottom } from './chat-render-runtime.js';
|
|
6
|
+
import { openMateWorkspace } from './project-mate-navigation.js';
|
|
7
|
+
import { createHomeDebateQuestionCard, createHomeDebateProposalCard, normalizeHomeTranscript, applyHomeDebateProposal, resolveHomeDebateProposal, failHomeDebateQuestion } from './home-debate-planning.js';
|
|
8
|
+
import { refreshIcons, iconHtml } from './icons.js';
|
|
9
|
+
|
|
10
|
+
var root = null;
|
|
11
|
+
var sequence = 0;
|
|
12
|
+
var liveReplaySessionId = null;
|
|
13
|
+
var suppressLiveSetupReplay = false;
|
|
14
|
+
|
|
15
|
+
function send(message) {
|
|
16
|
+
var ws = getWs();
|
|
17
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
18
|
+
ws.send(JSON.stringify(message));
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function clayMate() {
|
|
23
|
+
var mates = store.get('cachedMatesList') || [];
|
|
24
|
+
for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].builtinKey === 'clay') return mates[i];
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function requestId() { sequence += 1; return 'project-debate-planning-' + Date.now() + '-' + sequence; }
|
|
29
|
+
function same(left, right) { return left != null && right != null && String(left) === String(right); }
|
|
30
|
+
|
|
31
|
+
function context() {
|
|
32
|
+
return { mateId: store.get('projectDebatePlanningMateId'), sessionId: store.get('projectDebatePlanningSessionId'), requestId: store.get('projectDebatePlanningRequestId') };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function messages() { return store.get('projectDebatePlanningMessages') || []; }
|
|
36
|
+
function setMessages(value) { store.set({ projectDebatePlanningMessages: value }); }
|
|
37
|
+
|
|
38
|
+
function retryPlanning() {
|
|
39
|
+
var state = store.snap();
|
|
40
|
+
store.set({ projectDebatePlanningError: '', projectDebatePlanningRetryable: false });
|
|
41
|
+
if (!state.projectDebatePlanningSessionId) {
|
|
42
|
+
store.set({ projectDebatePlanningPendingStart: true });
|
|
43
|
+
maybeStart();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
var id = requestId();
|
|
47
|
+
if (!send({ type: 'home_mate_debate_plan', mateId: state.projectDebatePlanningMateId, sessionId: state.projectDebatePlanningSessionId, topic: state.projectDebatePlanningTopic, requestId: id })) {
|
|
48
|
+
store.set({ projectDebatePlanningError: 'Reconnect to retry debate setup.', projectDebatePlanningRetryable: true });
|
|
49
|
+
render();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
store.set({ projectDebatePlanningRequestId: id, projectDebatePlanningAwaitingHistory: true });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function ensureRoot() {
|
|
56
|
+
if (root && root.isConnected) return root;
|
|
57
|
+
root = document.createElement('section');
|
|
58
|
+
root.className = 'project-debate-planning-transcript home-mate-chat-transcript home-chat-bubble-layout';
|
|
59
|
+
root.setAttribute('aria-label', 'Debate setup');
|
|
60
|
+
addToMessages(root);
|
|
61
|
+
return root;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function respondToQuestion(message, action, opener, answers) {
|
|
65
|
+
if (!message || message.status === 'submitting') return;
|
|
66
|
+
if (!send(Object.assign({ type: 'home_debate_question_response', toolId: message.toolId, answers: answers || {} }, context()))) return;
|
|
67
|
+
setMessages(messages().map(function (item) { return item === message ? Object.assign({}, item, { status: 'submitting' }) : item; }));
|
|
68
|
+
render();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function respondToProposal(message, action, opener, answers, modelOverrides) {
|
|
72
|
+
if (!message || message.status === 'submitting') return;
|
|
73
|
+
if (!send(Object.assign({ type: 'home_debate_proposal_response', proposalId: message.proposal.proposalId, action: action === 'start' ? 'start' : 'cancel', modelOverrides: modelOverrides || [] }, context()))) return;
|
|
74
|
+
setMessages(messages().map(function (item) { return item === message ? Object.assign({}, item, { status: 'submitting' }) : item; }));
|
|
75
|
+
render();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function render() {
|
|
79
|
+
var container = ensureRoot();
|
|
80
|
+
container.innerHTML = '';
|
|
81
|
+
var intro = document.createElement('header');
|
|
82
|
+
intro.className = 'project-mate-creation-intro';
|
|
83
|
+
intro.innerHTML = iconHtml('messages-square') + '<span>Plan a debate with Clay</span>';
|
|
84
|
+
container.appendChild(intro);
|
|
85
|
+
var list = messages();
|
|
86
|
+
for (var i = 0; i < list.length; i++) {
|
|
87
|
+
if (list[i].role === 'question') container.appendChild(createHomeDebateQuestionCard(list[i], respondToQuestion));
|
|
88
|
+
if (list[i].role === 'proposal') container.appendChild(createHomeDebateProposalCard(list[i], respondToProposal));
|
|
89
|
+
}
|
|
90
|
+
var errorText = store.get('projectDebatePlanningError');
|
|
91
|
+
if (errorText) {
|
|
92
|
+
var error = document.createElement('section');
|
|
93
|
+
error.className = 'project-debate-planning-error';
|
|
94
|
+
error.setAttribute('role', 'alert');
|
|
95
|
+
var copy = document.createElement('p');
|
|
96
|
+
copy.textContent = errorText;
|
|
97
|
+
error.appendChild(copy);
|
|
98
|
+
if (store.get('projectDebatePlanningRetryable')) {
|
|
99
|
+
var retry = document.createElement('button');
|
|
100
|
+
retry.type = 'button';
|
|
101
|
+
retry.textContent = 'Retry debate setup';
|
|
102
|
+
retry.addEventListener('click', retryPlanning);
|
|
103
|
+
error.appendChild(retry);
|
|
104
|
+
}
|
|
105
|
+
container.appendChild(error);
|
|
106
|
+
}
|
|
107
|
+
scrollToBottom();
|
|
108
|
+
refreshIcons();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function clear() {
|
|
112
|
+
root = null;
|
|
113
|
+
store.set({ projectDebatePlanningActive: false, projectDebatePlanningMateId: null, projectDebatePlanningSessionId: null, projectDebatePlanningLocalId: null, projectDebatePlanningRequestId: null, projectDebatePlanningPendingStart: false, projectDebatePlanningAwaitingHistory: false, projectDebatePlanningAwaitingMateList: false, projectDebatePlanningHistoryReady: false, projectDebatePlanningTopic: '', projectDebatePlanningMessages: [], projectDebatePlanningError: '', projectDebatePlanningRetryable: false });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function maybeStart() {
|
|
117
|
+
var state = store.snap();
|
|
118
|
+
if (!state.projectDebatePlanningPendingStart || !state.connected || state.activeProjectSlug !== 'mate-' + state.projectDebatePlanningMateId) return;
|
|
119
|
+
var id = requestId();
|
|
120
|
+
if (!send({ type: 'home_mate_debate_plan', mateId: state.projectDebatePlanningMateId, topic: state.projectDebatePlanningTopic, requestId: id })) return;
|
|
121
|
+
store.set({ projectDebatePlanningPendingStart: false, projectDebatePlanningAwaitingHistory: true, projectDebatePlanningRequestId: id });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function startProjectDebatePlanning(topic) {
|
|
125
|
+
var clay = clayMate();
|
|
126
|
+
if (!clay) {
|
|
127
|
+
store.set({ projectDebatePlanningError: 'Clay is unavailable. Refresh and try again.', projectDebatePlanningRetryable: false });
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
root = null;
|
|
131
|
+
store.set({ projectDebatePlanningActive: true, projectDebatePlanningMateId: clay.id, projectDebatePlanningSessionId: null, projectDebatePlanningLocalId: null, projectDebatePlanningRequestId: null, projectDebatePlanningPendingStart: true, projectDebatePlanningAwaitingHistory: false, projectDebatePlanningAwaitingMateList: false, projectDebatePlanningHistoryReady: false, projectDebatePlanningTopic: typeof topic === 'string' ? topic.trim().slice(0, 1000) : '', projectDebatePlanningMessages: [], projectDebatePlanningError: '', projectDebatePlanningRetryable: false });
|
|
132
|
+
openMateWorkspace(clay.id);
|
|
133
|
+
maybeStart();
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function exact(msg, allowUnbound) {
|
|
138
|
+
var state = store.snap();
|
|
139
|
+
if (!state.projectDebatePlanningActive || !same(msg.mateId, state.projectDebatePlanningMateId) || !same(msg.requestId, state.projectDebatePlanningRequestId)) return false;
|
|
140
|
+
if (!state.projectDebatePlanningSessionId) return allowUnbound === true;
|
|
141
|
+
return same(msg.sessionId, state.projectDebatePlanningSessionId);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function openHistory(msg) {
|
|
145
|
+
if (!exact(msg, store.get('projectDebatePlanningAwaitingHistory') && !store.get('projectDebatePlanningSessionId'))) return false;
|
|
146
|
+
store.set({ projectDebatePlanningSessionId: msg.sessionId, projectDebatePlanningLocalId: typeof msg.localId === 'number' ? msg.localId : store.get('projectDebatePlanningLocalId'), projectDebatePlanningAwaitingHistory: false });
|
|
147
|
+
if (typeof msg.localId === 'number' && String(store.get('activeSessionId')) !== String(msg.localId)) {
|
|
148
|
+
send({ type: 'switch_session', id: msg.localId });
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
setMessages(normalizeHomeTranscript(msg.messages || []).filter(function (message) { return message.role === 'question' || message.role === 'proposal'; }));
|
|
152
|
+
render();
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function resume() {
|
|
157
|
+
var state = store.snap();
|
|
158
|
+
if (!state.projectDebatePlanningActive || !state.projectDebatePlanningMateId || !state.projectDebatePlanningSessionId) return;
|
|
159
|
+
var id = requestId();
|
|
160
|
+
if (!send({ type: 'home_mate_session_open', mateId: state.projectDebatePlanningMateId, sessionId: state.projectDebatePlanningSessionId, requestId: id })) return;
|
|
161
|
+
store.set({ projectDebatePlanningRequestId: id, projectDebatePlanningAwaitingHistory: true });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function activateRestored(msg, clay) {
|
|
165
|
+
root = null;
|
|
166
|
+
store.set({ projectDebatePlanningActive: true, projectDebatePlanningMateId: clay.id, projectDebatePlanningSessionId: msg.cliSessionId || 'local:' + msg.id, projectDebatePlanningLocalId: msg.id, projectDebatePlanningRequestId: requestId(), projectDebatePlanningPendingStart: false, projectDebatePlanningAwaitingHistory: false, projectDebatePlanningAwaitingMateList: false, projectDebatePlanningHistoryReady: false, projectDebatePlanningTopic: '', projectDebatePlanningMessages: [] });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function restoreAfterMateList() {
|
|
170
|
+
var state = store.snap();
|
|
171
|
+
if (!state.projectDebatePlanningAwaitingMateList) return;
|
|
172
|
+
var clay = clayMate();
|
|
173
|
+
if (!clay || state.currentSlug !== 'mate-' + clay.id || state.projectDebatePlanningLocalId == null) return;
|
|
174
|
+
var historyReady = state.projectDebatePlanningHistoryReady;
|
|
175
|
+
activateRestored({ id: state.projectDebatePlanningLocalId, cliSessionId: state.projectDebatePlanningSessionId && state.projectDebatePlanningSessionId.indexOf('local:') !== 0 ? state.projectDebatePlanningSessionId : null }, clay);
|
|
176
|
+
if (historyReady) resume();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function handleProjectDebatePlanningMessage(msg) {
|
|
180
|
+
if (msg.type === 'session_switched') {
|
|
181
|
+
if (msg.debatePlanning === true && msg.debatePhase === 'live') {
|
|
182
|
+
clear();
|
|
183
|
+
liveReplaySessionId = msg.id;
|
|
184
|
+
suppressLiveSetupReplay = true;
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
liveReplaySessionId = null;
|
|
188
|
+
suppressLiveSetupReplay = false;
|
|
189
|
+
var clay = clayMate();
|
|
190
|
+
var state = store.snap();
|
|
191
|
+
var starting = msg.debatePlanning === true && state.projectDebatePlanningActive && state.projectDebatePlanningAwaitingHistory && !state.projectDebatePlanningSessionId && state.currentSlug === 'mate-' + state.projectDebatePlanningMateId;
|
|
192
|
+
if (starting) store.set({ projectDebatePlanningSessionId: msg.cliSessionId || 'local:' + msg.id, projectDebatePlanningLocalId: msg.id, projectDebatePlanningMessages: [] });
|
|
193
|
+
else if (msg.debatePlanning === true && clay && state.currentSlug === 'mate-' + clay.id) activateRestored(msg, clay);
|
|
194
|
+
else if (msg.debatePlanning === true && !clay && /^mate-/.test(state.currentSlug || '')) store.set({ projectDebatePlanningActive: false, projectDebatePlanningAwaitingMateList: true, projectDebatePlanningHistoryReady: false, projectDebatePlanningLocalId: msg.id, projectDebatePlanningSessionId: msg.cliSessionId || 'local:' + msg.id, projectDebatePlanningMessages: [] });
|
|
195
|
+
else if (!(state.projectDebatePlanningActive && (state.projectDebatePlanningPendingStart || state.projectDebatePlanningAwaitingHistory) && state.currentSlug === 'mate-' + state.projectDebatePlanningMateId && !state.projectDebatePlanningSessionId)) clear();
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
if (msg.type === 'home_mate_session_identity') {
|
|
199
|
+
var identityState = store.snap();
|
|
200
|
+
if (!identityState.projectDebatePlanningActive || !same(msg.mateId, identityState.projectDebatePlanningMateId) || !same(msg.requestId, identityState.projectDebatePlanningRequestId) || !same(msg.previousSessionId, identityState.projectDebatePlanningSessionId) || !msg.sessionId) return false;
|
|
201
|
+
store.set({ projectDebatePlanningSessionId: msg.sessionId });
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
if (msg.type === 'home_debate_event' && msg.eventType === 'debate_started') {
|
|
205
|
+
suppressLiveSetupReplay = false;
|
|
206
|
+
if (store.get('projectDebatePlanningActive')) clear();
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (msg.type === 'debate_started' && suppressLiveSetupReplay && same(store.get('activeSessionId'), liveReplaySessionId)) {
|
|
210
|
+
suppressLiveSetupReplay = false;
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
if (suppressLiveSetupReplay && same(store.get('activeSessionId'), liveReplaySessionId)
|
|
214
|
+
&& ((msg.type === 'tool_executing' && msg.name === 'AskUserQuestion') || msg.type === 'ask_user_answered'
|
|
215
|
+
|| msg.type === 'debate_proposal' || msg.type === 'debate_proposal_resolved' || msg.type === 'delta'
|
|
216
|
+
|| msg.type === 'result' || msg.type === 'done' || msg.type === 'error')) return true;
|
|
217
|
+
if (msg.type === 'history_done') {
|
|
218
|
+
if (store.get('projectDebatePlanningAwaitingMateList')) store.set({ projectDebatePlanningHistoryReady: true });
|
|
219
|
+
else if (!store.get('projectDebatePlanningAwaitingHistory')) resume();
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
var raw = (msg.type === 'tool_executing' && msg.name === 'AskUserQuestion') || msg.type === 'debate_proposal' || msg.type === 'debate_proposal_resolved' || msg.type === 'ask_user_answered' || msg.type === 'delta' || msg.type === 'result' || msg.type === 'done' || msg.type === 'error' || msg.type === 'home_mate_delta' || msg.type === 'home_mate_done';
|
|
223
|
+
if (raw && store.get('projectDebatePlanningAwaitingMateList')) return same(store.get('activeSessionId'), store.get('projectDebatePlanningLocalId'));
|
|
224
|
+
if (!store.get('projectDebatePlanningActive')) return false;
|
|
225
|
+
if (msg.type === 'home_mate_history' && msg.debatePlanning === true) return openHistory(msg);
|
|
226
|
+
if (raw) return same(store.get('activeSessionId'), store.get('projectDebatePlanningLocalId'));
|
|
227
|
+
if (!exact(msg, msg.type === 'home_mate_error' && store.get('projectDebatePlanningAwaitingHistory'))) return false;
|
|
228
|
+
if (msg.type === 'home_debate_question') {
|
|
229
|
+
setMessages(messages().concat([{ role: 'question', flow: 'debate', toolId: msg.toolId, questions: msg.questions || [], status: 'pending', error: '' }])); render(); return true;
|
|
230
|
+
}
|
|
231
|
+
if (msg.type === 'home_debate_question_resolved') {
|
|
232
|
+
setMessages(messages().map(function (item) { return item.role === 'question' && item.toolId === msg.toolId ? Object.assign({}, item, { status: msg.status === 'answered' ? 'answered' : 'expired', answers: msg.answers || null, error: msg.error || '' }) : item; })); render(); return true;
|
|
233
|
+
}
|
|
234
|
+
if (msg.type === 'home_debate_proposal') { setMessages(applyHomeDebateProposal(messages(), msg)); render(); return true; }
|
|
235
|
+
if (msg.type === 'home_debate_proposal_resolved') { setMessages(resolveHomeDebateProposal(messages(), msg)); render(); return true; }
|
|
236
|
+
if (msg.type === 'home_mate_error') {
|
|
237
|
+
if (/^question_/.test(msg.code || '')) setMessages(failHomeDebateQuestion(messages(), msg));
|
|
238
|
+
else store.set({ projectDebatePlanningError: msg.text || 'Debate setup could not continue.', projectDebatePlanningRetryable: true, projectDebatePlanningAwaitingHistory: false });
|
|
239
|
+
render();
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function initProjectDebatePlanningWorkspace() {
|
|
246
|
+
store.subscribe(function (state, previous) {
|
|
247
|
+
if (state.projectDebatePlanningPendingStart !== previous.projectDebatePlanningPendingStart || state.connected !== previous.connected || state.activeProjectSlug !== previous.activeProjectSlug) maybeStart();
|
|
248
|
+
if (state.cachedMatesList !== previous.cachedMatesList) restoreAfterMateList();
|
|
249
|
+
});
|
|
250
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// Adapt project events to the shared Home debate presentation.
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import { getWs } from './ws-ref.js';
|
|
4
|
+
import { getMessagesEl } from './dom-refs.js';
|
|
5
|
+
import { addToMessages, scrollToBottom } from './chat-render-runtime.js';
|
|
6
|
+
import { isMateWorkspace } from './project-mate-navigation.js';
|
|
7
|
+
import { applyHomeDebateEvent, createHomeDebateLiveCard } from './home-debate-live.js';
|
|
8
|
+
import { createHomeDebateProposalCard, applyHomeDebateProposal, resolveHomeDebateProposal } from './home-debate-planning.js';
|
|
9
|
+
import { createDebateControls } from './debate-controls.js';
|
|
10
|
+
import { renderAssistantBubbleText, finalizeAssistantBubble, disposeChatBubbleTree } from './chat-bubble-renderer.js';
|
|
11
|
+
|
|
12
|
+
var transcriptEl = null;
|
|
13
|
+
var prependEl = null;
|
|
14
|
+
var controls = createDebateControls({
|
|
15
|
+
slotId: 'project-debate-controls',
|
|
16
|
+
composerId: 'input-area',
|
|
17
|
+
send: function (action, data, sessionId) {
|
|
18
|
+
var ws = getWs();
|
|
19
|
+
if (!ws || ws.readyState !== 1 || String(store.get('activeSessionId')) !== sessionId) return false;
|
|
20
|
+
ws.send(JSON.stringify({ type: 'project_debate_control', sessionId: store.get('activeSessionId'), action: action, text: data.text || '', response: data.response || null }));
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function stateKey() {
|
|
26
|
+
return store.get('projectDebatePrepending') ? 'projectDebatePrependMessages' : 'projectDebateMessages';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ensureTranscript() {
|
|
30
|
+
var prepending = store.get('projectDebatePrepending');
|
|
31
|
+
var root = prepending ? prependEl : transcriptEl;
|
|
32
|
+
if (!root || !root.isConnected) {
|
|
33
|
+
root = document.createElement('section');
|
|
34
|
+
root.className = 'project-debate-transcript home-mate-chat-transcript home-chat-bubble-layout';
|
|
35
|
+
root.setAttribute('aria-label', 'Debate transcript');
|
|
36
|
+
addToMessages(root);
|
|
37
|
+
if (prepending) prependEl = root;
|
|
38
|
+
else transcriptEl = root;
|
|
39
|
+
}
|
|
40
|
+
return root;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function renderControls() {
|
|
44
|
+
var slot = document.getElementById('project-debate-controls');
|
|
45
|
+
var composer = document.getElementById('input-area');
|
|
46
|
+
if (!slot && composer) {
|
|
47
|
+
slot = document.createElement('div');
|
|
48
|
+
slot.id = 'project-debate-controls';
|
|
49
|
+
slot.className = 'home-debate-controls-slot project-debate-controls';
|
|
50
|
+
slot.hidden = true;
|
|
51
|
+
composer.parentNode.insertBefore(slot, composer);
|
|
52
|
+
}
|
|
53
|
+
controls.render(store.get('projectDebateMessages') || [], String(store.get('activeSessionId') || ''));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function respondToProposal(message, action, opener, answers, modelOverrides) {
|
|
57
|
+
var ws = getWs();
|
|
58
|
+
if (!ws || ws.readyState !== 1 || message.status === 'submitting') return;
|
|
59
|
+
ws.send(JSON.stringify({ type: 'debate_proposal_response', proposalId: message.proposal.proposalId, sessionId: store.get('activeSessionId'), action: action, modelOverrides: modelOverrides || [] }));
|
|
60
|
+
var messages = (store.get('projectDebateMessages') || []).map(function (item) {
|
|
61
|
+
return item === message ? Object.assign({}, item, { status: 'submitting' }) : item;
|
|
62
|
+
});
|
|
63
|
+
store.set({ projectDebateMessages: messages });
|
|
64
|
+
renderMessages(messages);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderMessages(messages) {
|
|
68
|
+
var root = ensureTranscript();
|
|
69
|
+
messages.forEach(function (message, index) {
|
|
70
|
+
var existing = root.children[index];
|
|
71
|
+
if (existing && existing._debateMessage === message) return;
|
|
72
|
+
if (existing && message.role === 'debate_turn' && existing.classList.contains('home-debate-live-turn')) {
|
|
73
|
+
var activity = existing.querySelector('.home-debate-live-activity');
|
|
74
|
+
if (message.status === 'done') {
|
|
75
|
+
if (activity) activity.remove();
|
|
76
|
+
finalizeAssistantBubble(existing, message.text || '', !store.get('replayingHistory'));
|
|
77
|
+
} else {
|
|
78
|
+
if (activity) {
|
|
79
|
+
var label = message.activity || (message.text ? 'Speaking' : 'Preparing');
|
|
80
|
+
activity.firstChild.textContent = label;
|
|
81
|
+
activity.setAttribute('aria-label', (message.mateName || 'Mate') + ' is ' + label.toLowerCase());
|
|
82
|
+
}
|
|
83
|
+
renderAssistantBubbleText(existing, message.text || '', false);
|
|
84
|
+
}
|
|
85
|
+
existing._debateMessage = message;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
var card = message.role === 'proposal'
|
|
89
|
+
? createHomeDebateProposalCard(message, respondToProposal)
|
|
90
|
+
: createHomeDebateLiveCard(message, message.status === 'done');
|
|
91
|
+
card._debateMessage = message;
|
|
92
|
+
if (existing) { disposeChatBubbleTree(existing); existing.replaceWith(card); }
|
|
93
|
+
else root.appendChild(card);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function resetProjectDebateWorkspace() {
|
|
98
|
+
store.set({ projectDebateMessages: [], projectDebatePrependMessages: [], projectDebatePrepending: false });
|
|
99
|
+
transcriptEl = null;
|
|
100
|
+
prependEl = null;
|
|
101
|
+
controls.render([], null);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function beginProjectDebatePrepend() {
|
|
105
|
+
prependEl = null;
|
|
106
|
+
store.set({ projectDebatePrepending: true, projectDebatePrependMessages: [] });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function endProjectDebatePrepend() {
|
|
110
|
+
prependEl = null;
|
|
111
|
+
store.set({ projectDebatePrepending: false, projectDebatePrependMessages: [] });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function handleProjectDebateMessage(msg) {
|
|
115
|
+
if (!isMateWorkspace(store.snap())) return false;
|
|
116
|
+
if (msg.type === 'project_debate_control_result') {
|
|
117
|
+
if (String(msg.sessionId) !== String(store.get('activeSessionId'))) return true;
|
|
118
|
+
if (!msg.ok) {
|
|
119
|
+
controls.render([], null);
|
|
120
|
+
renderControls();
|
|
121
|
+
var slot = document.getElementById('project-debate-controls');
|
|
122
|
+
var error = document.createElement('p');
|
|
123
|
+
error.className = 'project-debate-error';
|
|
124
|
+
error.setAttribute('role', 'alert');
|
|
125
|
+
error.textContent = msg.error || 'The debate action could not be completed.';
|
|
126
|
+
if (slot) slot.appendChild(error);
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (msg.type === 'history_done') {
|
|
131
|
+
renderControls();
|
|
132
|
+
var ws = getWs();
|
|
133
|
+
if (ws && ws.readyState === 1 && (store.get('projectDebateMessages') || []).length) {
|
|
134
|
+
ws.send(JSON.stringify({ type: 'project_debate_state', sessionId: store.get('activeSessionId') }));
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (msg.type === 'project_debate_state') {
|
|
139
|
+
if (String(msg.sessionId) !== String(store.get('activeSessionId')) || !msg.header) return true;
|
|
140
|
+
var restored = (store.get('projectDebateMessages') || []).slice();
|
|
141
|
+
var headerIndex = -1;
|
|
142
|
+
restored.forEach(function (item, index) { if (item.role === 'debate_header') headerIndex = index; });
|
|
143
|
+
if (headerIndex === -1) restored.unshift(msg.header);
|
|
144
|
+
else restored[headerIndex] = msg.header;
|
|
145
|
+
if (msg.header.phase !== 'live') restored = restored.map(function (item) {
|
|
146
|
+
return item.role === 'debate_turn' && item.status === 'active' ? Object.assign({}, item, { status: 'done', activity: '' }) : item;
|
|
147
|
+
});
|
|
148
|
+
store.set({ projectDebateMessages: restored });
|
|
149
|
+
renderMessages(restored);
|
|
150
|
+
renderControls();
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (msg.type === 'debate_preparing') {
|
|
154
|
+
var root = ensureTranscript();
|
|
155
|
+
var preparation = document.createElement('p');
|
|
156
|
+
preparation.className = 'debate-preparing-indicator home-debate-live-status';
|
|
157
|
+
preparation.setAttribute('role', 'status');
|
|
158
|
+
preparation.textContent = (msg.moderatorName || 'The moderator') + ' is preparing the debate…';
|
|
159
|
+
root.appendChild(preparation);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (msg.type === 'tool_executing' && msg.name && msg.name.indexOf('propose_debate') !== -1) return true;
|
|
163
|
+
var types = ['debate_started', 'debate_turn', 'debate_activity', 'debate_stream', 'debate_turn_done', 'debate_tool_decision', 'debate_stop_requested', 'debate_stop_cancelled', 'debate_hand_raised', 'debate_conclude_confirm', 'debate_user_floor', 'debate_user_floor_done', 'debate_comment_injected', 'debate_user_resume', 'debate_resumed', 'debate_ended', 'debate_proposal', 'debate_proposal_resolved'];
|
|
164
|
+
if (types.indexOf(msg.type) === -1) return false;
|
|
165
|
+
var key = stateKey();
|
|
166
|
+
var messages = store.get(key) || [];
|
|
167
|
+
if (msg.type === 'debate_tool_decision') messages = messages.map(function (item) {
|
|
168
|
+
return item.role === 'debate_tool_decision' ? Object.assign({}, item, { entries: (item.entries || []).slice() }) : item;
|
|
169
|
+
});
|
|
170
|
+
if (msg.type === 'debate_proposal') messages = applyHomeDebateProposal(messages, msg);
|
|
171
|
+
else if (msg.type === 'debate_proposal_resolved') messages = resolveHomeDebateProposal(messages, msg);
|
|
172
|
+
else messages = applyHomeDebateEvent(messages, Object.assign({}, msg, { eventType: msg.type, speakerMateId: msg.mateId }));
|
|
173
|
+
if (msg.type === 'debate_ended') messages = messages.map(function (item) {
|
|
174
|
+
return item.role === 'debate_turn' && item.status === 'active' ? Object.assign({}, item, { status: 'done', activity: '' }) : item;
|
|
175
|
+
});
|
|
176
|
+
var patch = {};
|
|
177
|
+
patch[key] = messages;
|
|
178
|
+
store.set(patch);
|
|
179
|
+
var preparation = getMessagesEl().querySelector('.debate-preparing-indicator');
|
|
180
|
+
if (preparation) preparation.remove();
|
|
181
|
+
renderMessages(messages);
|
|
182
|
+
if (!store.get('projectDebatePrepending') && !store.get('replayingHistory')) renderControls();
|
|
183
|
+
scrollToBottom();
|
|
184
|
+
return true;
|
|
185
|
+
}
|