clay-server 2.26.0-beta.11 → 2.26.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/project-debate.js +10 -3
- package/lib/public/app.js +47 -75
- package/lib/public/css/debate.css +6 -0
- package/lib/sdk-bridge.js +24 -5
- package/lib/sessions.js +2 -8
- package/package.json +1 -1
package/lib/project-debate.js
CHANGED
|
@@ -1542,9 +1542,15 @@ function attachDebate(ctx) {
|
|
|
1542
1542
|
avatarSeed: moderatorProfile.avatarSeed,
|
|
1543
1543
|
});
|
|
1544
1544
|
|
|
1545
|
+
// Build explicit panelist list so the moderator knows who to call on
|
|
1546
|
+
var panelistNames = debate.panelists.map(function (p) {
|
|
1547
|
+
var prof = ctx.getMateProfile(mateCtx, p.mateId);
|
|
1548
|
+
return "@" + prof.name;
|
|
1549
|
+
});
|
|
1550
|
+
var panelistList = panelistNames.join(", ");
|
|
1545
1551
|
var resumePrompt = instruction
|
|
1546
|
-
? "[The audience has requested the debate continue with
|
|
1547
|
-
: "[The audience has requested the debate continue.
|
|
1552
|
+
? "[SYSTEM: The audience has requested the debate continue with new direction. You MUST call on a panelist to continue. Available panelists: " + panelistList + "]\n\nUser direction: " + instruction + "\n\n[Acknowledge this input briefly, then call on a panelist by writing their @Name to continue the discussion on this new direction. You must @mention exactly one panelist.]"
|
|
1553
|
+
: "[SYSTEM: The audience has requested the debate continue. You MUST call on the next panelist. Available panelists: " + panelistList + "]\n\n[Call on a panelist by writing their @Name to explore additional perspectives. You must @mention exactly one panelist.]";
|
|
1548
1554
|
|
|
1549
1555
|
// If resuming from ended state, moderator session may be dead. Create a new one.
|
|
1550
1556
|
if (wasEnded || !debate.moderatorSession || !debate.moderatorSession.isAlive()) {
|
|
@@ -1554,7 +1560,8 @@ function attachDebate(ctx) {
|
|
|
1554
1560
|
var moderatorContext = buildModeratorContext(debate) + digests;
|
|
1555
1561
|
|
|
1556
1562
|
// Include debate history so moderator has context
|
|
1557
|
-
moderatorContext += "\n\
|
|
1563
|
+
moderatorContext += "\n\nIMPORTANT: This debate was previously paused and is now being RESUMED. You must continue the debate by calling on a panelist with @TheirName. Do NOT conclude or summarize.\n";
|
|
1564
|
+
moderatorContext += "\nDebate history so far:\n---\n";
|
|
1558
1565
|
for (var hi = 0; hi < debate.history.length; hi++) {
|
|
1559
1566
|
var h = debate.history[hi];
|
|
1560
1567
|
moderatorContext += (h.mateName || h.speaker || "Unknown") + " (" + (h.role || "") + "): " + (h.text || "").slice(0, 500) + "\n\n";
|
package/lib/public/app.js
CHANGED
|
@@ -5872,8 +5872,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5872
5872
|
handleDmSend: function () { handleDmSend(); },
|
|
5873
5873
|
isDebateEndedMode: function () { return debateEndedMode; },
|
|
5874
5874
|
handleDebateEndedSend: function () { handleDebateEndedSend(); },
|
|
5875
|
-
isDebateConcludeMode: function () { return
|
|
5876
|
-
handleDebateConcludeSend:
|
|
5875
|
+
isDebateConcludeMode: function () { return false; },
|
|
5876
|
+
handleDebateConcludeSend: null,
|
|
5877
5877
|
isDebateFloorMode: function () { return debateFloorMode; },
|
|
5878
5878
|
handleDebateFloorSend: function () { handleDebateFloorSend(); },
|
|
5879
5879
|
isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
|
|
@@ -7201,70 +7201,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7201
7201
|
}
|
|
7202
7202
|
|
|
7203
7203
|
var debateFloorMode = false;
|
|
7204
|
-
var debateConcludeMode = false;
|
|
7205
|
-
|
|
7206
|
-
function showDebateConcludeMode() {
|
|
7207
|
-
debateConcludeMode = true;
|
|
7208
|
-
removeDebateBottomBar();
|
|
7209
|
-
var inputArea = document.getElementById("input-area");
|
|
7210
|
-
if (inputArea) {
|
|
7211
|
-
inputArea.classList.add("debate-floor-mode");
|
|
7212
|
-
inputArea.style.display = "";
|
|
7213
|
-
}
|
|
7214
|
-
// Add conclude banner above input
|
|
7215
|
-
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7216
|
-
if (existingBanner) existingBanner.remove();
|
|
7217
|
-
var banner = document.createElement("div");
|
|
7218
|
-
banner.id = "debate-floor-banner";
|
|
7219
|
-
banner.className = "debate-floor-banner";
|
|
7220
|
-
banner.innerHTML = iconHtml("check-circle") + " <span>The moderator is ready to conclude</span>" +
|
|
7221
|
-
'<button class="debate-floor-done-btn debate-floor-end-btn" id="debate-floor-end-btn">End Debate</button>';
|
|
7222
|
-
if (inputArea && inputArea.parentNode) {
|
|
7223
|
-
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7224
|
-
}
|
|
7225
|
-
refreshIcons();
|
|
7226
|
-
// End Debate button
|
|
7227
|
-
var endBtn = document.getElementById("debate-floor-end-btn");
|
|
7228
|
-
if (endBtn) {
|
|
7229
|
-
endBtn.addEventListener("click", function () {
|
|
7230
|
-
if (ws && ws.readyState === 1) {
|
|
7231
|
-
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "end" }));
|
|
7232
|
-
}
|
|
7233
|
-
exitDebateConcludeMode();
|
|
7234
|
-
});
|
|
7235
|
-
}
|
|
7236
|
-
// Update placeholder
|
|
7237
|
-
var inputEl = document.getElementById("input");
|
|
7238
|
-
if (inputEl) {
|
|
7239
|
-
inputEl._origPlaceholder = inputEl._origPlaceholder || inputEl.placeholder;
|
|
7240
|
-
inputEl.placeholder = "Add a direction to continue the debate...";
|
|
7241
|
-
inputEl.focus();
|
|
7242
|
-
}
|
|
7243
|
-
scrollToBottom();
|
|
7244
|
-
}
|
|
7245
|
-
|
|
7246
|
-
function exitDebateConcludeMode() {
|
|
7247
|
-
debateConcludeMode = false;
|
|
7248
|
-
var inputArea = document.getElementById("input-area");
|
|
7249
|
-
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7250
|
-
var banner = document.getElementById("debate-floor-banner");
|
|
7251
|
-
if (banner) banner.remove();
|
|
7252
|
-
var inputEl = document.getElementById("input");
|
|
7253
|
-
if (inputEl && inputEl._origPlaceholder) {
|
|
7254
|
-
inputEl.placeholder = inputEl._origPlaceholder;
|
|
7255
|
-
delete inputEl._origPlaceholder;
|
|
7256
|
-
}
|
|
7257
|
-
}
|
|
7258
|
-
|
|
7259
|
-
function handleDebateConcludeSend() {
|
|
7260
|
-
var text = inputEl.value.trim();
|
|
7261
|
-
if (ws && ws.readyState === 1) {
|
|
7262
|
-
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7263
|
-
}
|
|
7264
|
-
inputEl.value = "";
|
|
7265
|
-
exitDebateConcludeMode();
|
|
7266
|
-
showDebateBottomBar("live");
|
|
7267
|
-
}
|
|
7268
7204
|
|
|
7269
7205
|
var debateEndedMode = false;
|
|
7270
7206
|
|
|
@@ -7439,7 +7375,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7439
7375
|
return;
|
|
7440
7376
|
}
|
|
7441
7377
|
|
|
7442
|
-
//
|
|
7378
|
+
// Show bottom bar regardless of header availability
|
|
7379
|
+
if (phase === "live") {
|
|
7380
|
+
debateHandRaiseOpen = false;
|
|
7381
|
+
showDebateBottomBar("live");
|
|
7382
|
+
}
|
|
7383
|
+
|
|
7384
|
+
// Add badges next to header title (optional, may not exist on mobile)
|
|
7443
7385
|
var headerTitle = document.getElementById("header-title");
|
|
7444
7386
|
if (!headerTitle) return;
|
|
7445
7387
|
|
|
@@ -7459,9 +7401,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7459
7401
|
roundBadge.id = "debate-header-round";
|
|
7460
7402
|
roundBadge.textContent = "R" + ((msg && msg.round) || 1);
|
|
7461
7403
|
liveBadge.after(roundBadge);
|
|
7462
|
-
|
|
7463
|
-
debateHandRaiseOpen = false;
|
|
7464
|
-
showDebateBottomBar("live");
|
|
7465
7404
|
}
|
|
7466
7405
|
}
|
|
7467
7406
|
|
|
@@ -7505,9 +7444,43 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7505
7444
|
}
|
|
7506
7445
|
});
|
|
7507
7446
|
} else if (mode === "conclude") {
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7447
|
+
bar.innerHTML =
|
|
7448
|
+
'<div class="debate-bottom-inner debate-bottom-conclude">' +
|
|
7449
|
+
'<div class="debate-bottom-conclude-label">' + iconHtml("check-circle") + ' The moderator is ready to conclude. End the debate?</div>' +
|
|
7450
|
+
'<textarea class="debate-bottom-conclude-input" id="debate-bottom-conclude-input" rows="3" placeholder="Or add a direction to continue..."></textarea>' +
|
|
7451
|
+
'<div class="debate-bottom-conclude-actions">' +
|
|
7452
|
+
'<button class="debate-bottom-continue" id="debate-bottom-continue">Continue</button>' +
|
|
7453
|
+
'<button class="debate-bottom-end" id="debate-bottom-end">End Debate</button>' +
|
|
7454
|
+
'</div>' +
|
|
7455
|
+
'</div>';
|
|
7456
|
+
|
|
7457
|
+
inputArea.parentNode.insertBefore(bar, inputArea);
|
|
7458
|
+
inputArea.style.display = "none";
|
|
7459
|
+
refreshIcons();
|
|
7460
|
+
|
|
7461
|
+
var textArea = document.getElementById("debate-bottom-conclude-input");
|
|
7462
|
+
document.getElementById("debate-bottom-end").addEventListener("click", function () {
|
|
7463
|
+
if (ws && ws.readyState === 1) {
|
|
7464
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "end" }));
|
|
7465
|
+
}
|
|
7466
|
+
removeDebateBottomBar();
|
|
7467
|
+
});
|
|
7468
|
+
document.getElementById("debate-bottom-continue").addEventListener("click", function () {
|
|
7469
|
+
var text = textArea ? textArea.value.trim() : "";
|
|
7470
|
+
if (ws && ws.readyState === 1) {
|
|
7471
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7472
|
+
}
|
|
7473
|
+
removeDebateBottomBar();
|
|
7474
|
+
showDebateBottomBar("live");
|
|
7475
|
+
});
|
|
7476
|
+
if (textArea) {
|
|
7477
|
+
textArea.addEventListener("keydown", function (e) {
|
|
7478
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
7479
|
+
e.preventDefault();
|
|
7480
|
+
document.getElementById("debate-bottom-continue").click();
|
|
7481
|
+
}
|
|
7482
|
+
});
|
|
7483
|
+
}
|
|
7511
7484
|
}
|
|
7512
7485
|
}
|
|
7513
7486
|
|
|
@@ -7527,9 +7500,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7527
7500
|
var handBar = document.getElementById("debate-hand-raise-bar");
|
|
7528
7501
|
if (handBar) handBar.remove();
|
|
7529
7502
|
debateHandRaiseOpen = false;
|
|
7530
|
-
// Clean up floor/
|
|
7503
|
+
// Clean up floor/ended modes
|
|
7531
7504
|
if (debateFloorMode) exitDebateFloorMode();
|
|
7532
|
-
if (debateConcludeMode) exitDebateConcludeMode();
|
|
7533
7505
|
if (debateEndedMode) exitDebateEndedMode();
|
|
7534
7506
|
// Restore input area
|
|
7535
7507
|
var inputArea = document.getElementById("input-area");
|
|
@@ -1302,6 +1302,12 @@
|
|
|
1302
1302
|
padding: 12px 16px;
|
|
1303
1303
|
}
|
|
1304
1304
|
|
|
1305
|
+
@media (max-width: 768px) {
|
|
1306
|
+
#debate-bottom-bar {
|
|
1307
|
+
padding-bottom: calc(12px + 56px + var(--safe-bottom, 0px));
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1305
1311
|
.debate-bottom-inner {
|
|
1306
1312
|
max-width: var(--content-width);
|
|
1307
1313
|
margin: 0 auto;
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -437,9 +437,32 @@ function createSDKBridge(opts) {
|
|
|
437
437
|
session.pendingAskUser = {};
|
|
438
438
|
session.activeTaskToolIds = {};
|
|
439
439
|
session.taskIdMap = {};
|
|
440
|
-
session.isProcessing = false;
|
|
441
440
|
session.rateLimitResetsAt = null; // clear on success
|
|
441
|
+
|
|
442
|
+
// Handle SDK execution errors: show the error to the user instead of
|
|
443
|
+
// silently swallowing it. These have subtype "error_during_execution".
|
|
444
|
+
if (parsed.subtype === "error_during_execution") {
|
|
445
|
+
var execErrors = parsed.errors || [];
|
|
446
|
+
var execError = execErrors.length > 0
|
|
447
|
+
? execErrors.join("; ")
|
|
448
|
+
: "Unknown SDK error";
|
|
449
|
+
if (parsed.terminal_reason) execError += " (reason: " + parsed.terminal_reason + ")";
|
|
450
|
+
console.error("[sdk-bridge] Execution error for session " + session.localId + ": " + execError);
|
|
451
|
+
session.isProcessing = false;
|
|
452
|
+
onProcessingChanged();
|
|
453
|
+
sendAndRecord(session, { type: "error", text: "Claude error: " + execError });
|
|
454
|
+
sendAndRecord(session, { type: "done", code: 1 });
|
|
455
|
+
sm.broadcastSessionList();
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
session.isProcessing = false;
|
|
442
460
|
onProcessingChanged();
|
|
461
|
+
// Detect "Not logged in" scenario early for the check below
|
|
462
|
+
var previewTrimmed = (session.responsePreview || "").trim();
|
|
463
|
+
var isZeroCost = !parsed.total_cost_usd || parsed.total_cost_usd === 0;
|
|
464
|
+
var isLoginPrompt = isZeroCost && previewTrimmed.length < 100
|
|
465
|
+
&& /not logged in/i.test(previewTrimmed) && /\/login/i.test(previewTrimmed);
|
|
443
466
|
// Fetch rich context usage breakdown (fire-and-forget, non-blocking)
|
|
444
467
|
if (session.queryInstance && typeof session.queryInstance.getContextUsage === "function") {
|
|
445
468
|
session.queryInstance.getContextUsage().then(function(ctxUsage) {
|
|
@@ -465,10 +488,6 @@ function createSDKBridge(opts) {
|
|
|
465
488
|
}
|
|
466
489
|
// Detect "Not logged in · Please run /login" from SDK.
|
|
467
490
|
// This is a short canned response with zero cost, not actual AI output.
|
|
468
|
-
var previewTrimmed = (session.responsePreview || "").trim();
|
|
469
|
-
var isZeroCost = !parsed.total_cost_usd || parsed.total_cost_usd === 0;
|
|
470
|
-
var isLoginPrompt = isZeroCost && previewTrimmed.length < 100
|
|
471
|
-
&& /not logged in/i.test(previewTrimmed) && /\/login/i.test(previewTrimmed);
|
|
472
491
|
if (isLoginPrompt) {
|
|
473
492
|
var authUser = session.ownerId ? usersModule.findUserById(session.ownerId) : null;
|
|
474
493
|
var authLinuxUser = authUser && authUser.linuxUser ? authUser.linuxUser : null;
|
package/lib/sessions.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
var fs = require("fs");
|
|
2
2
|
var path = require("path");
|
|
3
|
-
var crypto = require("crypto");
|
|
4
3
|
var config = require("./config");
|
|
5
4
|
var utils = require("./utils");
|
|
6
5
|
var users = require("./users");
|
|
@@ -76,9 +75,7 @@ function createSessionManager(opts) {
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
function saveSessionFile(session) {
|
|
79
|
-
if (!session.cliSessionId)
|
|
80
|
-
session.cliSessionId = crypto.randomUUID();
|
|
81
|
-
}
|
|
78
|
+
if (!session.cliSessionId) return;
|
|
82
79
|
try {
|
|
83
80
|
var metaObj = {
|
|
84
81
|
type: "meta",
|
|
@@ -113,10 +110,7 @@ function createSessionManager(opts) {
|
|
|
113
110
|
}
|
|
114
111
|
|
|
115
112
|
function appendToSessionFile(session, obj) {
|
|
116
|
-
if (!session.cliSessionId)
|
|
117
|
-
session.cliSessionId = crypto.randomUUID();
|
|
118
|
-
saveSessionFile(session);
|
|
119
|
-
}
|
|
113
|
+
if (!session.cliSessionId) return;
|
|
120
114
|
session.lastActivity = Date.now();
|
|
121
115
|
try {
|
|
122
116
|
var afPath = sessionFilePath(session.cliSessionId);
|
package/package.json
CHANGED