clay-server 2.26.0-beta.12 → 2.26.0-beta.14
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 +40 -71
- package/lib/sdk-bridge.js +29 -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
|
|
|
@@ -7508,9 +7444,43 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7508
7444
|
}
|
|
7509
7445
|
});
|
|
7510
7446
|
} else if (mode === "conclude") {
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
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
|
+
}
|
|
7514
7484
|
}
|
|
7515
7485
|
}
|
|
7516
7486
|
|
|
@@ -7530,9 +7500,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7530
7500
|
var handBar = document.getElementById("debate-hand-raise-bar");
|
|
7531
7501
|
if (handBar) handBar.remove();
|
|
7532
7502
|
debateHandRaiseOpen = false;
|
|
7533
|
-
// Clean up floor/
|
|
7503
|
+
// Clean up floor/ended modes
|
|
7534
7504
|
if (debateFloorMode) exitDebateFloorMode();
|
|
7535
|
-
if (debateConcludeMode) exitDebateConcludeMode();
|
|
7536
7505
|
if (debateEndedMode) exitDebateEndedMode();
|
|
7537
7506
|
// Restore input area
|
|
7538
7507
|
var inputArea = document.getElementById("input-area");
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -437,9 +437,37 @@ function createSDKBridge(opts) {
|
|
|
437
437
|
session.pendingAskUser = {};
|
|
438
438
|
session.activeTaskToolIds = {};
|
|
439
439
|
session.taskIdMap = {};
|
|
440
|
+
// Only clear rateLimitResetsAt on genuine success (non-zero cost).
|
|
441
|
+
// When rate-limited, the SDK sends result with zero cost right after
|
|
442
|
+
// rate_limit_event; clearing here would prevent auto-continue scheduling.
|
|
443
|
+
if (parsed.total_cost_usd && parsed.total_cost_usd > 0) {
|
|
444
|
+
session.rateLimitResetsAt = null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Handle SDK execution errors: show the error to the user instead of
|
|
448
|
+
// silently swallowing it. These have subtype "error_during_execution".
|
|
449
|
+
if (parsed.subtype === "error_during_execution") {
|
|
450
|
+
var execErrors = parsed.errors || [];
|
|
451
|
+
var execError = execErrors.length > 0
|
|
452
|
+
? execErrors.join("; ")
|
|
453
|
+
: "Unknown SDK error";
|
|
454
|
+
if (parsed.terminal_reason) execError += " (reason: " + parsed.terminal_reason + ")";
|
|
455
|
+
console.error("[sdk-bridge] Execution error for session " + session.localId + ": " + execError);
|
|
456
|
+
session.isProcessing = false;
|
|
457
|
+
onProcessingChanged();
|
|
458
|
+
sendAndRecord(session, { type: "error", text: "Claude error: " + execError });
|
|
459
|
+
sendAndRecord(session, { type: "done", code: 1 });
|
|
460
|
+
sm.broadcastSessionList();
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
440
464
|
session.isProcessing = false;
|
|
441
|
-
session.rateLimitResetsAt = null; // clear on success
|
|
442
465
|
onProcessingChanged();
|
|
466
|
+
// Detect "Not logged in" scenario early for the check below
|
|
467
|
+
var previewTrimmed = (session.responsePreview || "").trim();
|
|
468
|
+
var isZeroCost = !parsed.total_cost_usd || parsed.total_cost_usd === 0;
|
|
469
|
+
var isLoginPrompt = isZeroCost && previewTrimmed.length < 100
|
|
470
|
+
&& /not logged in/i.test(previewTrimmed) && /\/login/i.test(previewTrimmed);
|
|
443
471
|
// Fetch rich context usage breakdown (fire-and-forget, non-blocking)
|
|
444
472
|
if (session.queryInstance && typeof session.queryInstance.getContextUsage === "function") {
|
|
445
473
|
session.queryInstance.getContextUsage().then(function(ctxUsage) {
|
|
@@ -465,10 +493,6 @@ function createSDKBridge(opts) {
|
|
|
465
493
|
}
|
|
466
494
|
// Detect "Not logged in · Please run /login" from SDK.
|
|
467
495
|
// 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
496
|
if (isLoginPrompt) {
|
|
473
497
|
var authUser = session.ownerId ? usersModule.findUserById(session.ownerId) : null;
|
|
474
498
|
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