clay-server 3.8.1 → 4.0.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/lib/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
package/lib/project-debate.js
CHANGED
|
@@ -2,6 +2,7 @@ var fs = require("fs");
|
|
|
2
2
|
var path = require("path");
|
|
3
3
|
var crypto = require("crypto");
|
|
4
4
|
var matesModule = require("./mates");
|
|
5
|
+
var debateToolPolicy = require("./home-debate-tool-policy");
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Attach debate engine to a project context.
|
|
@@ -95,6 +96,7 @@ function attachDebate(ctx) {
|
|
|
95
96
|
lines.push("4. After hearing from all panelists, you may start additional rounds.");
|
|
96
97
|
lines.push("5. When you believe the debate has reached a natural conclusion, provide a summary WITHOUT mentioning any panelist. A response with no @mention signals the end of the debate.");
|
|
97
98
|
lines.push("6. If the user interjects with a comment, acknowledge it and weave it into the discussion.");
|
|
99
|
+
lines.push("7. You govern debate tool access: non-mutating investigation is permitted and shown to the user, while any capability that could change the system is blocked.");
|
|
98
100
|
lines.push("");
|
|
99
101
|
lines.push("Begin by introducing the topic and calling on the first panelist.");
|
|
100
102
|
return lines.join("\n");
|
|
@@ -125,23 +127,43 @@ function attachDebate(ctx) {
|
|
|
125
127
|
lines.push("2. Respond to the specific question or prompt from the moderator.");
|
|
126
128
|
lines.push("3. You may reference what other panelists have said.");
|
|
127
129
|
lines.push("4. Keep responses focused and substantive. Do not ramble.");
|
|
128
|
-
lines.push("5. You
|
|
130
|
+
lines.push("5. You may use investigation tools when they strengthen your argument. The moderator automatically permits non-mutating research and blocks system changes.");
|
|
129
131
|
return lines.join("\n");
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
function buildDebateToolHandler(session) {
|
|
134
|
+
function buildDebateToolHandler(session, mateId) {
|
|
133
135
|
return function (toolName, input, toolOpts) {
|
|
134
|
-
var
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
var decision = debateToolPolicy.debateToolDecision(toolName, input);
|
|
137
|
+
var debate = session && session._debate;
|
|
138
|
+
var profile = debate ? ctx.getMateProfile(debate.mateCtx, mateId) : null;
|
|
139
|
+
debateSendAndRecord(session, {
|
|
140
|
+
type: "debate_tool_decision",
|
|
141
|
+
decisionId: toolOpts && toolOpts.toolUseID ? toolOpts.toolUseID : crypto.randomUUID(),
|
|
142
|
+
mateId: mateId || null,
|
|
143
|
+
mateName: profile && profile.name ? profile.name : "Mate",
|
|
144
|
+
toolName: debateToolPolicy.displayToolName(toolName),
|
|
145
|
+
action: decision.action,
|
|
146
|
+
command: decision.command,
|
|
147
|
+
commandTruncated: decision.commandTruncated,
|
|
148
|
+
decision: decision.allowed ? "allowed" : "blocked",
|
|
149
|
+
reason: decision.reason,
|
|
150
|
+
});
|
|
138
151
|
return Promise.resolve({
|
|
139
|
-
behavior:
|
|
140
|
-
|
|
152
|
+
behavior: decision.behavior,
|
|
153
|
+
updatedInput: decision.updatedInput,
|
|
154
|
+
message: decision.message,
|
|
141
155
|
});
|
|
142
156
|
};
|
|
143
157
|
}
|
|
144
158
|
|
|
159
|
+
function participantModel(debate, mateId) {
|
|
160
|
+
var selections = debate && Array.isArray(debate.participantModels) ? debate.participantModels : [];
|
|
161
|
+
for (var i = 0; i < selections.length; i++) {
|
|
162
|
+
if (selections[i] && selections[i].mateId === mateId) return selections[i];
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
// --- State persistence ---
|
|
146
168
|
|
|
147
169
|
function persistDebateState(session) {
|
|
@@ -154,6 +176,9 @@ function attachDebate(ctx) {
|
|
|
154
176
|
context: d.context || "",
|
|
155
177
|
specialRequests: d.specialRequests || null,
|
|
156
178
|
moderatorId: d.moderatorId,
|
|
179
|
+
participantModels: Array.isArray(d.participantModels) ? d.participantModels.map(function (item) {
|
|
180
|
+
return { mateId: item.mateId, vendor: item.vendor, model: item.model };
|
|
181
|
+
}) : [],
|
|
157
182
|
panelists: d.panelists.map(function (p) {
|
|
158
183
|
return { mateId: p.mateId, role: p.role || "", brief: p.brief || "" };
|
|
159
184
|
}),
|
|
@@ -165,6 +190,7 @@ function attachDebate(ctx) {
|
|
|
165
190
|
awaitingConcludeConfirm: !!d.awaitingConcludeConfirm,
|
|
166
191
|
awaitingUserFloor: !!d.awaitingUserFloor,
|
|
167
192
|
ownerId: d.ownerId || null,
|
|
193
|
+
turnSequence: d.turnSequence || 0,
|
|
168
194
|
};
|
|
169
195
|
ctx.sm.saveSessionFile(session);
|
|
170
196
|
}
|
|
@@ -181,6 +207,7 @@ function attachDebate(ctx) {
|
|
|
181
207
|
context: ds.context || "",
|
|
182
208
|
specialRequests: ds.specialRequests || null,
|
|
183
209
|
moderatorId: ds.moderatorId,
|
|
210
|
+
participantModels: Array.isArray(ds.participantModels) ? ds.participantModels : [],
|
|
184
211
|
panelists: ds.panelists || [],
|
|
185
212
|
mateCtx: mateCtx,
|
|
186
213
|
moderatorSession: null,
|
|
@@ -197,6 +224,7 @@ function attachDebate(ctx) {
|
|
|
197
224
|
awaitingConcludeConfirm: !!ds.awaitingConcludeConfirm,
|
|
198
225
|
awaitingUserFloor: !!ds.awaitingUserFloor,
|
|
199
226
|
ownerId: ds.ownerId || userId,
|
|
227
|
+
turnSequence: ds.turnSequence || 0,
|
|
200
228
|
};
|
|
201
229
|
|
|
202
230
|
// Fallback: if awaitingConcludeConfirm was not persisted, detect from history
|
|
@@ -337,11 +365,24 @@ function attachDebate(ctx) {
|
|
|
337
365
|
// On server restart, SDK sessions are lost so debates cannot continue.
|
|
338
366
|
// Clear stale debate state instead of restoring dead UI.
|
|
339
367
|
ctx.sm.sessions.forEach(function (session) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
368
|
+
// A live in-memory debate belongs to this daemon and must survive a
|
|
369
|
+
// websocket reconnect. Persisted state without its runtime object is
|
|
370
|
+
// the restart case that cannot safely resume dead mention processes.
|
|
371
|
+
if (session._debate) return;
|
|
343
372
|
if (session.debateState) {
|
|
344
373
|
var phase = session.debateState.phase;
|
|
374
|
+
if (session.homeDebatePlanning === true && (phase === "live" || phase === "ending")) {
|
|
375
|
+
session.homeDebatePhase = "interrupted";
|
|
376
|
+
session.debateState.phase = "interrupted";
|
|
377
|
+
var lastLifecycle = null;
|
|
378
|
+
for (var li = session.history.length - 1; li >= 0; li--) {
|
|
379
|
+
var lifecycleType = session.history[li] && session.history[li].type;
|
|
380
|
+
if (lifecycleType === "debate_started" || lifecycleType === "debate_resumed" || lifecycleType === "debate_ended") { lastLifecycle = lifecycleType; break; }
|
|
381
|
+
}
|
|
382
|
+
if (lastLifecycle !== "debate_ended") session.history.push({ type: "debate_ended", topic: session.debateState.topic || session.title || "Debate", rounds: session.debateState.round || 1, reason: "interrupted", _ts: Date.now() });
|
|
383
|
+
ctx.sm.saveSessionFile(session);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
345
386
|
if (phase === "preparing" || phase === "reviewing" || phase === "live") {
|
|
346
387
|
console.log("[debate] Clearing stale debate state:", session.debateState.topic);
|
|
347
388
|
session.debateState = null;
|
|
@@ -726,14 +767,31 @@ function attachDebate(ctx) {
|
|
|
726
767
|
|
|
727
768
|
// Persist a debate message to session history and send to clients
|
|
728
769
|
function debateSendAndRecord(session, msg) {
|
|
729
|
-
session.
|
|
730
|
-
|
|
731
|
-
|
|
770
|
+
var debate = session._debate;
|
|
771
|
+
if (debate && msg.mateId && (msg.type === "debate_turn" || msg.type === "debate_turn_done")) {
|
|
772
|
+
var identity = ctx.getMateProfile(debate.mateCtx, msg.mateId);
|
|
773
|
+
var identityMate = matesModule.getMate(debate.mateCtx, msg.mateId);
|
|
774
|
+
var identityProfile = identityMate && identityMate.profile ? identityMate.profile : (identityMate || {});
|
|
775
|
+
if (!msg.mateName) msg.mateName = identity.name;
|
|
776
|
+
if (!msg.avatarStyle) msg.avatarStyle = identity.avatarStyle;
|
|
777
|
+
if (!msg.avatarSeed) msg.avatarSeed = identity.avatarSeed;
|
|
778
|
+
if (!msg.avatarColor) msg.avatarColor = identity.avatarColor;
|
|
779
|
+
if (!msg.avatarCustom && identityProfile.avatarCustom) msg.avatarCustom = identityProfile.avatarCustom;
|
|
780
|
+
}
|
|
781
|
+
if (debate && msg.type === "debate_turn") {
|
|
782
|
+
debate.turnSequence = (debate.turnSequence || 0) + 1;
|
|
783
|
+
debate.activeTurnId = (debate.debateId || "debate") + ":" + debate.turnSequence;
|
|
784
|
+
msg.turnId = debate.activeTurnId;
|
|
785
|
+
} else if (debate && !msg.turnId && (msg.type === "debate_activity" || msg.type === "debate_stream" || msg.type === "debate_turn_done")) {
|
|
786
|
+
msg.turnId = debate.activeTurnId || null;
|
|
787
|
+
}
|
|
788
|
+
ctx.sm.sendAndRecord(session, msg);
|
|
789
|
+
if (debate && msg.type === "debate_turn_done") debate.activeTurnId = null;
|
|
732
790
|
}
|
|
733
791
|
|
|
734
792
|
// --- Live debate ---
|
|
735
793
|
|
|
736
|
-
function startDebateLive(session) {
|
|
794
|
+
function startDebateLive(session, targetWs) {
|
|
737
795
|
var debate = session._debate;
|
|
738
796
|
if (!debate || debate.phase === "live") return;
|
|
739
797
|
|
|
@@ -744,21 +802,35 @@ function attachDebate(ctx) {
|
|
|
744
802
|
var mateCtx = debate.mateCtx;
|
|
745
803
|
var moderatorProfile = ctx.getMateProfile(mateCtx, debate.moderatorId);
|
|
746
804
|
|
|
747
|
-
|
|
748
|
-
var
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
805
|
+
var reuseHomeSession = session.homeDebatePlanning === true;
|
|
806
|
+
var debateSession = session;
|
|
807
|
+
if (reuseHomeSession) {
|
|
808
|
+
session.homeDebatePhase = "live";
|
|
809
|
+
session.title = "Debate: " + debate.topic.slice(0, 42);
|
|
810
|
+
session.titleManuallySet = true;
|
|
811
|
+
session.isProcessing = false;
|
|
812
|
+
ctx.onProcessingChanged();
|
|
813
|
+
if (session.abortController) { try { session.abortController.abort(); } catch (e) {} }
|
|
814
|
+
if (session.queryInstance && typeof session.queryInstance.close === "function") { try { session.queryInstance.close(); } catch (e) {} }
|
|
815
|
+
session.abortController = null;
|
|
816
|
+
session.queryInstance = null;
|
|
817
|
+
if (session.messageQueue && typeof session.messageQueue.end === "function") { try { session.messageQueue.end(); } catch (e) {} }
|
|
818
|
+
session.messageQueue = null;
|
|
819
|
+
if (targetWs) targetWs._clayActiveSession = session.localId;
|
|
820
|
+
} else {
|
|
821
|
+
// Legacy project debates retain their dedicated live session.
|
|
822
|
+
var liveOpts = debate.ownerId ? { ownerId: debate.ownerId } : null;
|
|
823
|
+
debateSession = ctx.sm.createSession(liveOpts, targetWs || null);
|
|
824
|
+
debateSession.title = debate.topic.slice(0, 50);
|
|
825
|
+
debateSession.loop = { active: true, iteration: 1, role: "debate", loopId: debate.debateId, name: debate.topic.slice(0, 40), source: "debate", startedAt: debate.setupStartedAt || Date.now() };
|
|
826
|
+
ctx.sm.saveSessionFile(debateSession);
|
|
827
|
+
ctx.sm.switchSession(debateSession.localId, null, ctx.hydrateImageRefs);
|
|
828
|
+
debate.liveSessionId = debateSession.localId;
|
|
829
|
+
debateSession._debate = debate;
|
|
830
|
+
delete session._debate;
|
|
831
|
+
session.debateState = null;
|
|
832
|
+
ctx.sm.saveSessionFile(session);
|
|
833
|
+
}
|
|
762
834
|
persistDebateState(debateSession);
|
|
763
835
|
|
|
764
836
|
// Save to session history
|
|
@@ -768,16 +840,15 @@ function attachDebate(ctx) {
|
|
|
768
840
|
format: debate.format,
|
|
769
841
|
moderatorId: debate.moderatorId,
|
|
770
842
|
moderatorName: moderatorProfile.name,
|
|
843
|
+
participantModels: Array.isArray(debate.participantModels) ? debate.participantModels.map(function (item) {
|
|
844
|
+
return { mateId: item.mateId, vendor: item.vendor, model: item.model };
|
|
845
|
+
}) : [],
|
|
771
846
|
panelists: debate.panelists.map(function (p) {
|
|
772
847
|
var prof = ctx.getMateProfile(mateCtx, p.mateId);
|
|
773
848
|
return { mateId: p.mateId, name: prof.name, role: p.role, avatarColor: prof.avatarColor, avatarStyle: prof.avatarStyle, avatarSeed: prof.avatarSeed };
|
|
774
849
|
}),
|
|
775
850
|
};
|
|
776
|
-
debateSession
|
|
777
|
-
ctx.sm.appendToSessionFile(debateSession, debateStartEntry);
|
|
778
|
-
|
|
779
|
-
// Notify clients (same data as history entry)
|
|
780
|
-
ctx.sendToSession(debateSession.localId, debateStartEntry);
|
|
851
|
+
debateSendAndRecord(debateSession, debateStartEntry);
|
|
781
852
|
|
|
782
853
|
// Signal moderator's first turn
|
|
783
854
|
debateMateProcessing(debate.moderatorId, true);
|
|
@@ -798,15 +869,17 @@ function attachDebate(ctx) {
|
|
|
798
869
|
var moderatorContext = buildModeratorContext(debate) + digests;
|
|
799
870
|
|
|
800
871
|
var _modMate2 = matesModule.getMate(mateCtx, debate.moderatorId);
|
|
872
|
+
var moderatorModel = participantModel(debate, debate.moderatorId);
|
|
801
873
|
ctx.sdk.createMentionSession({
|
|
802
|
-
vendor: _modMate2 ? _modMate2.vendor : null,
|
|
874
|
+
vendor: moderatorModel ? moderatorModel.vendor : (_modMate2 ? _modMate2.vendor : null),
|
|
875
|
+
model: moderatorModel ? moderatorModel.model : undefined,
|
|
803
876
|
linuxUser: mateCtx.linuxUser || undefined,
|
|
804
877
|
claudeMd: claudeMd,
|
|
805
878
|
initialContext: moderatorContext,
|
|
806
879
|
initialMessage: "Begin the debate on: " + debate.topic,
|
|
807
880
|
onActivity: function (activity) {
|
|
808
881
|
if (debateSession._debate && debateSession._debate.phase !== "ended") {
|
|
809
|
-
|
|
882
|
+
debateSendAndRecord(debateSession, { type: "debate_activity", mateId: debate.moderatorId, activity: activity });
|
|
810
883
|
}
|
|
811
884
|
},
|
|
812
885
|
onDelta: function (delta) {
|
|
@@ -821,7 +894,7 @@ function attachDebate(ctx) {
|
|
|
821
894
|
console.error("[debate] Moderator error:", errMsg);
|
|
822
895
|
endDebate(debateSession, "error");
|
|
823
896
|
},
|
|
824
|
-
canUseTool: buildDebateToolHandler(debateSession),
|
|
897
|
+
canUseTool: buildDebateToolHandler(debateSession, debate.moderatorId),
|
|
825
898
|
}).then(function (mentionSession) {
|
|
826
899
|
if (mentionSession) {
|
|
827
900
|
debate.moderatorSession = mentionSession;
|
|
@@ -847,9 +920,7 @@ function attachDebate(ctx) {
|
|
|
847
920
|
|
|
848
921
|
// Save to session history
|
|
849
922
|
var turnEntry = { type: "debate_turn_done", mateId: debate.moderatorId, mateName: moderatorProfile.name, role: "moderator", round: debate.round, text: fullText, avatarStyle: moderatorProfile.avatarStyle, avatarSeed: moderatorProfile.avatarSeed, avatarColor: moderatorProfile.avatarColor };
|
|
850
|
-
session
|
|
851
|
-
ctx.sm.appendToSessionFile(session, turnEntry);
|
|
852
|
-
ctx.sendToSession(session.localId, turnEntry);
|
|
923
|
+
debateSendAndRecord(session, turnEntry);
|
|
853
924
|
|
|
854
925
|
// Check if user stopped the debate during this turn
|
|
855
926
|
if (debate.phase === "ending") {
|
|
@@ -870,9 +941,7 @@ function attachDebate(ctx) {
|
|
|
870
941
|
debate.awaitingConcludeConfirm = true;
|
|
871
942
|
persistDebateState(session);
|
|
872
943
|
var concludeEntry = { type: "debate_conclude_confirm", topic: debate.topic, round: debate.round };
|
|
873
|
-
session
|
|
874
|
-
ctx.sm.appendToSessionFile(session, concludeEntry);
|
|
875
|
-
ctx.sendToSession(session.localId, concludeEntry);
|
|
944
|
+
debateSendAndRecord(session, concludeEntry);
|
|
876
945
|
return;
|
|
877
946
|
}
|
|
878
947
|
|
|
@@ -933,7 +1002,7 @@ function attachDebate(ctx) {
|
|
|
933
1002
|
var panelistCallbacks = {
|
|
934
1003
|
onActivity: function (activity) {
|
|
935
1004
|
if (session._debate && session._debate.phase !== "ended") {
|
|
936
|
-
|
|
1005
|
+
debateSendAndRecord(session, { type: "debate_activity", mateId: mateId, activity: activity });
|
|
937
1006
|
}
|
|
938
1007
|
},
|
|
939
1008
|
onDelta: function (delta) {
|
|
@@ -994,8 +1063,10 @@ function attachDebate(ctx) {
|
|
|
994
1063
|
}
|
|
995
1064
|
|
|
996
1065
|
var _panMate = matesModule.getMate(debate.mateCtx, mateId);
|
|
1066
|
+
var panelistModel = participantModel(debate, mateId);
|
|
997
1067
|
ctx.sdk.createMentionSession({
|
|
998
|
-
vendor: _panMate ? _panMate.vendor : null,
|
|
1068
|
+
vendor: panelistModel ? panelistModel.vendor : (_panMate ? _panMate.vendor : null),
|
|
1069
|
+
model: panelistModel ? panelistModel.model : undefined,
|
|
999
1070
|
linuxUser: debate.mateCtx && debate.mateCtx.linuxUser ? debate.mateCtx.linuxUser : undefined,
|
|
1000
1071
|
claudeMd: claudeMd,
|
|
1001
1072
|
initialContext: panelistContext + historyContext,
|
|
@@ -1004,7 +1075,7 @@ function attachDebate(ctx) {
|
|
|
1004
1075
|
onDelta: panelistCallbacks.onDelta,
|
|
1005
1076
|
onDone: panelistCallbacks.onDone,
|
|
1006
1077
|
onError: panelistCallbacks.onError,
|
|
1007
|
-
canUseTool: buildDebateToolHandler(session),
|
|
1078
|
+
canUseTool: buildDebateToolHandler(session, mateId),
|
|
1008
1079
|
}).then(function (mentionSession) {
|
|
1009
1080
|
if (mentionSession) {
|
|
1010
1081
|
debate.panelistSessions[mateId] = mentionSession;
|
|
@@ -1041,9 +1112,7 @@ function attachDebate(ctx) {
|
|
|
1041
1112
|
|
|
1042
1113
|
// Save to session history
|
|
1043
1114
|
var turnEntry = { type: "debate_turn_done", mateId: mateId, mateName: profile.name, role: panelistInfo ? panelistInfo.role : "", round: debate.round, text: fullText, avatarStyle: profile.avatarStyle, avatarSeed: profile.avatarSeed, avatarColor: profile.avatarColor };
|
|
1044
|
-
session
|
|
1045
|
-
ctx.sm.appendToSessionFile(session, turnEntry);
|
|
1046
|
-
ctx.sendToSession(session.localId, turnEntry);
|
|
1115
|
+
debateSendAndRecord(session, turnEntry);
|
|
1047
1116
|
|
|
1048
1117
|
// Check if user stopped the debate
|
|
1049
1118
|
if (debate.phase === "ending") {
|
|
@@ -1112,7 +1181,7 @@ function attachDebate(ctx) {
|
|
|
1112
1181
|
return {
|
|
1113
1182
|
onActivity: function (activity) {
|
|
1114
1183
|
if (session._debate && session._debate.phase !== "ended") {
|
|
1115
|
-
|
|
1184
|
+
debateSendAndRecord(session, { type: "debate_activity", mateId: debate.moderatorId, activity: activity });
|
|
1116
1185
|
}
|
|
1117
1186
|
},
|
|
1118
1187
|
onDelta: function (delta) {
|
|
@@ -1132,20 +1201,21 @@ function attachDebate(ctx) {
|
|
|
1132
1201
|
|
|
1133
1202
|
// --- User interaction during debate ---
|
|
1134
1203
|
|
|
1135
|
-
function handleDebateHandRaise(ws) {
|
|
1136
|
-
var session = ctx.getSessionForWs(ws);
|
|
1204
|
+
function handleDebateHandRaise(ws, exactSession) {
|
|
1205
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1137
1206
|
if (!session) return;
|
|
1138
1207
|
|
|
1139
1208
|
var debate = session._debate;
|
|
1140
1209
|
if (!debate || debate.phase !== "live") return;
|
|
1141
1210
|
if (debate.awaitingUserFloor || debate.handRaised) return;
|
|
1142
1211
|
if (debate.awaitingConcludeConfirm) {
|
|
1143
|
-
|
|
1212
|
+
if (session.homeDebatePlanning === true) debateSendAndRecord(session, { type: "debate_conclude_confirm", topic: debate.topic, round: debate.round });
|
|
1213
|
+
else ctx.sendTo(ws, { type: "debate_conclude_confirm", topic: debate.topic, round: debate.round });
|
|
1144
1214
|
return;
|
|
1145
1215
|
}
|
|
1146
1216
|
|
|
1147
1217
|
debate.handRaised = true;
|
|
1148
|
-
|
|
1218
|
+
debateSendAndRecord(session, { type: "debate_hand_raised" });
|
|
1149
1219
|
|
|
1150
1220
|
// If no one is speaking, yield floor immediately
|
|
1151
1221
|
if (!debate.turnInProgress) {
|
|
@@ -1154,9 +1224,9 @@ function attachDebate(ctx) {
|
|
|
1154
1224
|
// Otherwise: current speaker finishes -> handRaised detected -> yieldFloorToUser
|
|
1155
1225
|
}
|
|
1156
1226
|
|
|
1157
|
-
function handleDebateComment(ws, msg) {
|
|
1227
|
+
function handleDebateComment(ws, msg, exactSession) {
|
|
1158
1228
|
// Legacy: kept for compatibility but now hand raise is separate
|
|
1159
|
-
var session = ctx.getSessionForWs(ws);
|
|
1229
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1160
1230
|
if (!session) return;
|
|
1161
1231
|
|
|
1162
1232
|
var debate = session._debate;
|
|
@@ -1169,7 +1239,7 @@ function attachDebate(ctx) {
|
|
|
1169
1239
|
|
|
1170
1240
|
debate.pendingComment = { text: msg.text };
|
|
1171
1241
|
debate.handRaised = true;
|
|
1172
|
-
|
|
1242
|
+
debateSendAndRecord(session, { type: "debate_comment_queued", text: msg.text });
|
|
1173
1243
|
|
|
1174
1244
|
if (!debate.turnInProgress) {
|
|
1175
1245
|
injectUserComment(session);
|
|
@@ -1215,9 +1285,7 @@ function attachDebate(ctx) {
|
|
|
1215
1285
|
debate.history.push({ speaker: "user", mateId: null, mateName: "User", text: comment.text });
|
|
1216
1286
|
|
|
1217
1287
|
var commentEntry = { type: "debate_comment_injected", text: comment.text };
|
|
1218
|
-
session
|
|
1219
|
-
ctx.sm.appendToSessionFile(session, commentEntry);
|
|
1220
|
-
ctx.sendToSession(session.localId, commentEntry);
|
|
1288
|
+
debateSendAndRecord(session, commentEntry);
|
|
1221
1289
|
|
|
1222
1290
|
// Feed to moderator: yield the floor to the user
|
|
1223
1291
|
debate.turnInProgress = true;
|
|
@@ -1249,7 +1317,7 @@ function attachDebate(ctx) {
|
|
|
1249
1317
|
return {
|
|
1250
1318
|
onActivity: function (activity) {
|
|
1251
1319
|
if (session._debate && session._debate.phase !== "ended") {
|
|
1252
|
-
|
|
1320
|
+
debateSendAndRecord(session, { type: "debate_activity", mateId: debate.moderatorId, activity: activity });
|
|
1253
1321
|
}
|
|
1254
1322
|
},
|
|
1255
1323
|
onDelta: function (delta) {
|
|
@@ -1264,14 +1332,12 @@ function attachDebate(ctx) {
|
|
|
1264
1332
|
// Record moderator yield turn
|
|
1265
1333
|
debate.history.push({ speaker: "moderator", mateId: debate.moderatorId, mateName: moderatorProfile.name, text: fullText });
|
|
1266
1334
|
var turnEntry = { type: "debate_turn_done", mateId: debate.moderatorId, mateName: moderatorProfile.name, role: "moderator", round: debate.round, text: fullText, avatarStyle: moderatorProfile.avatarStyle, avatarSeed: moderatorProfile.avatarSeed, avatarColor: moderatorProfile.avatarColor };
|
|
1267
|
-
session
|
|
1268
|
-
ctx.sm.appendToSessionFile(session, turnEntry);
|
|
1269
|
-
ctx.sendToSession(session.localId, turnEntry);
|
|
1335
|
+
debateSendAndRecord(session, turnEntry);
|
|
1270
1336
|
|
|
1271
1337
|
// Enter user floor mode: pause debate and show input
|
|
1272
1338
|
debate.awaitingUserFloor = true;
|
|
1273
1339
|
persistDebateState(session);
|
|
1274
|
-
|
|
1340
|
+
debateSendAndRecord(session, { type: "debate_user_floor", topic: debate.topic, round: debate.round });
|
|
1275
1341
|
},
|
|
1276
1342
|
onError: function (errMsg) {
|
|
1277
1343
|
console.error("[debate] Moderator yield error:", errMsg);
|
|
@@ -1280,8 +1346,8 @@ function attachDebate(ctx) {
|
|
|
1280
1346
|
};
|
|
1281
1347
|
}
|
|
1282
1348
|
|
|
1283
|
-
function handleDebateUserFloorResponse(ws, msg) {
|
|
1284
|
-
var session = ctx.getSessionForWs(ws);
|
|
1349
|
+
function handleDebateUserFloorResponse(ws, msg, exactSession) {
|
|
1350
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1285
1351
|
if (!session) return;
|
|
1286
1352
|
|
|
1287
1353
|
var debate = session._debate;
|
|
@@ -1294,9 +1360,7 @@ function attachDebate(ctx) {
|
|
|
1294
1360
|
// Record user's floor contribution
|
|
1295
1361
|
debate.history.push({ speaker: "user", mateId: null, mateName: "User", text: userText });
|
|
1296
1362
|
var floorEntry = { type: "debate_user_floor_done", text: userText };
|
|
1297
|
-
session
|
|
1298
|
-
ctx.sm.appendToSessionFile(session, floorEntry);
|
|
1299
|
-
ctx.sendToSession(session.localId, floorEntry);
|
|
1363
|
+
debateSendAndRecord(session, floorEntry);
|
|
1300
1364
|
|
|
1301
1365
|
// Feed to moderator to resume debate
|
|
1302
1366
|
debate.turnInProgress = true;
|
|
@@ -1336,40 +1400,54 @@ function attachDebate(ctx) {
|
|
|
1336
1400
|
startDebateLive(session);
|
|
1337
1401
|
}
|
|
1338
1402
|
|
|
1339
|
-
function handleDebateStop(ws) {
|
|
1340
|
-
var session = ctx.getSessionForWs(ws);
|
|
1341
|
-
if (!session) return;
|
|
1403
|
+
function handleDebateStop(ws, exactSession) {
|
|
1404
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1405
|
+
if (!session) return false;
|
|
1342
1406
|
|
|
1343
1407
|
var debate = session._debate;
|
|
1344
|
-
if (!debate) return;
|
|
1408
|
+
if (!debate) return false;
|
|
1345
1409
|
|
|
1346
1410
|
if (debate.phase === "reviewing") {
|
|
1347
1411
|
endDebate(session, "user_stopped");
|
|
1348
|
-
return;
|
|
1412
|
+
return true;
|
|
1349
1413
|
}
|
|
1350
1414
|
|
|
1351
|
-
if (debate.phase !== "live") return;
|
|
1415
|
+
if (debate.phase !== "live") return false;
|
|
1352
1416
|
|
|
1353
1417
|
if (debate.turnInProgress) {
|
|
1354
1418
|
// Let current turn finish, then end
|
|
1355
1419
|
debate.phase = "ending";
|
|
1420
|
+
persistDebateState(session);
|
|
1421
|
+
debateSendAndRecord(session, { type: "debate_stop_requested", topic: debate.topic, round: debate.round });
|
|
1356
1422
|
} else {
|
|
1357
1423
|
endDebate(session, "user_stopped");
|
|
1358
1424
|
}
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
function handleDebateCancelStop(ws, exactSession) {
|
|
1429
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1430
|
+
var debate = session && session._debate;
|
|
1431
|
+
if (!debate || debate.phase !== "ending") return false;
|
|
1432
|
+
debate.phase = "live";
|
|
1433
|
+
persistDebateState(session);
|
|
1434
|
+
debateSendAndRecord(session, { type: "debate_stop_cancelled", topic: debate.topic, round: debate.round });
|
|
1435
|
+
return true;
|
|
1359
1436
|
}
|
|
1360
1437
|
|
|
1361
1438
|
// Rebuild _debate from session history (for resume after server restart)
|
|
1362
1439
|
function rebuildDebateState(session, ws) {
|
|
1363
1440
|
// Find debate_started entry in history
|
|
1364
1441
|
var startEntry = null;
|
|
1365
|
-
var
|
|
1442
|
+
var latestPhase = null;
|
|
1366
1443
|
var concludeEntry = null;
|
|
1367
1444
|
var lastRound = 1;
|
|
1368
1445
|
for (var i = 0; i < session.history.length; i++) {
|
|
1369
1446
|
var h = session.history[i];
|
|
1370
|
-
if (h.type === "debate_started") startEntry = h;
|
|
1371
|
-
if (h.type === "
|
|
1372
|
-
if (h.type === "
|
|
1447
|
+
if (h.type === "debate_started") { startEntry = h; latestPhase = "live"; concludeEntry = null; }
|
|
1448
|
+
if (h.type === "debate_resumed") { latestPhase = "live"; concludeEntry = null; }
|
|
1449
|
+
if (h.type === "debate_ended") { latestPhase = "ended"; concludeEntry = null; }
|
|
1450
|
+
if (h.type === "debate_conclude_confirm" && latestPhase === "live") concludeEntry = h;
|
|
1373
1451
|
if (h.type === "debate_turn_done" && h.round) lastRound = h.round;
|
|
1374
1452
|
}
|
|
1375
1453
|
if (!startEntry) return null;
|
|
@@ -1377,29 +1455,33 @@ function attachDebate(ctx) {
|
|
|
1377
1455
|
var userId = ws._clayUser ? ws._clayUser.id : null;
|
|
1378
1456
|
var mateCtx = matesModule.buildMateCtx(userId);
|
|
1379
1457
|
|
|
1458
|
+
var savedState = session.debateState || {};
|
|
1459
|
+
var savedPanelists = Array.isArray(savedState.panelists) && savedState.panelists.length ? savedState.panelists : (startEntry.panelists || []);
|
|
1380
1460
|
var debate = {
|
|
1381
|
-
phase:
|
|
1382
|
-
topic: startEntry.topic || "",
|
|
1383
|
-
format: startEntry.format || "free_discussion",
|
|
1384
|
-
context: "",
|
|
1385
|
-
specialRequests: null,
|
|
1386
|
-
moderatorId: startEntry.moderatorId,
|
|
1387
|
-
|
|
1461
|
+
phase: session.homeDebatePhase === "ended" || session.homeDebatePhase === "interrupted" ? "ended" : (latestPhase || "live"),
|
|
1462
|
+
topic: savedState.topic || startEntry.topic || "",
|
|
1463
|
+
format: savedState.format || startEntry.format || "free_discussion",
|
|
1464
|
+
context: savedState.context || "",
|
|
1465
|
+
specialRequests: savedState.specialRequests || null,
|
|
1466
|
+
moderatorId: savedState.moderatorId || startEntry.moderatorId,
|
|
1467
|
+
participantModels: Array.isArray(savedState.participantModels) ? savedState.participantModels : (startEntry.participantModels || []),
|
|
1468
|
+
panelists: savedPanelists.map(function (p) {
|
|
1388
1469
|
return { mateId: p.mateId, role: p.role || "", brief: p.brief || "" };
|
|
1389
1470
|
}),
|
|
1390
1471
|
mateCtx: mateCtx,
|
|
1391
1472
|
moderatorSession: null,
|
|
1392
1473
|
panelistSessions: {},
|
|
1393
1474
|
nameMap: buildDebateNameMap(
|
|
1394
|
-
|
|
1475
|
+
savedPanelists.map(function (p) { return { mateId: p.mateId, role: p.role || "" }; }),
|
|
1395
1476
|
mateCtx
|
|
1396
1477
|
),
|
|
1397
1478
|
turnInProgress: false,
|
|
1398
1479
|
pendingComment: null,
|
|
1399
1480
|
round: lastRound,
|
|
1400
1481
|
history: [],
|
|
1401
|
-
awaitingConcludeConfirm:
|
|
1402
|
-
|
|
1482
|
+
awaitingConcludeConfirm: latestPhase === "live" && !!concludeEntry,
|
|
1483
|
+
ownerId: savedState.ownerId || userId,
|
|
1484
|
+
debateId: savedState.debateId || (session.loop && session.loop.loopId) || "debate_rebuilt",
|
|
1403
1485
|
};
|
|
1404
1486
|
|
|
1405
1487
|
// Rebuild debate.history from session history turn entries
|
|
@@ -1417,7 +1499,7 @@ function attachDebate(ctx) {
|
|
|
1417
1499
|
}
|
|
1418
1500
|
|
|
1419
1501
|
// If no endEntry and no concludeEntry, check if last moderator turn had no mentions (implicit conclude)
|
|
1420
|
-
if (
|
|
1502
|
+
if (debate.phase === "live" && !concludeEntry && debate.history.length > 0) {
|
|
1421
1503
|
var lastTurn = debate.history[debate.history.length - 1];
|
|
1422
1504
|
if (lastTurn.speaker === "moderator" && lastTurn.text) {
|
|
1423
1505
|
var rebuildMentions = detectMentions(lastTurn.text, debate.nameMap);
|
|
@@ -1433,8 +1515,8 @@ function attachDebate(ctx) {
|
|
|
1433
1515
|
return debate;
|
|
1434
1516
|
}
|
|
1435
1517
|
|
|
1436
|
-
function handleDebateConcludeResponse(ws, msg) {
|
|
1437
|
-
var session = ctx.getSessionForWs(ws);
|
|
1518
|
+
function handleDebateConcludeResponse(ws, msg, exactSession) {
|
|
1519
|
+
var session = exactSession || ctx.getSessionForWs(ws);
|
|
1438
1520
|
if (!session) return;
|
|
1439
1521
|
var debate = session._debate;
|
|
1440
1522
|
|
|
@@ -1449,7 +1531,7 @@ function attachDebate(ctx) {
|
|
|
1449
1531
|
|
|
1450
1532
|
// Allow resume from both "live + awaiting confirm" and "ended" states
|
|
1451
1533
|
var isLiveConfirm = debate.phase === "live" && debate.awaitingConcludeConfirm;
|
|
1452
|
-
var isResume = debate.phase === "ended" && msg.action === "continue";
|
|
1534
|
+
var isResume = (debate.phase === "ended" || debate.phase === "interrupted") && msg.action === "continue";
|
|
1453
1535
|
if (!isLiveConfirm && !isResume) return;
|
|
1454
1536
|
|
|
1455
1537
|
debate.awaitingConcludeConfirm = false;
|
|
@@ -1462,6 +1544,7 @@ function attachDebate(ctx) {
|
|
|
1462
1544
|
if (msg.action === "continue") {
|
|
1463
1545
|
var wasEnded = debate.phase === "ended";
|
|
1464
1546
|
debate.phase = "live";
|
|
1547
|
+
if (session.homeDebatePlanning === true) session.homeDebatePhase = "live";
|
|
1465
1548
|
var instruction = (msg.text || "").trim();
|
|
1466
1549
|
var mateCtx = debate.mateCtx || matesModule.buildMateCtx(ws._clayUser ? ws._clayUser.id : null);
|
|
1467
1550
|
debate.mateCtx = mateCtx;
|
|
@@ -1470,9 +1553,7 @@ function attachDebate(ctx) {
|
|
|
1470
1553
|
// Record user's resume message if provided
|
|
1471
1554
|
if (instruction) {
|
|
1472
1555
|
var resumeEntry = { type: "debate_user_resume", text: instruction };
|
|
1473
|
-
session
|
|
1474
|
-
ctx.sm.appendToSessionFile(session, resumeEntry);
|
|
1475
|
-
ctx.sendToSession(session.localId, resumeEntry);
|
|
1556
|
+
debateSendAndRecord(session, resumeEntry);
|
|
1476
1557
|
}
|
|
1477
1558
|
|
|
1478
1559
|
// Notify clients debate is back live and persist to history
|
|
@@ -1487,9 +1568,8 @@ function attachDebate(ctx) {
|
|
|
1487
1568
|
return { mateId: p.mateId, name: prof.name, role: p.role, avatarColor: prof.avatarColor, avatarStyle: prof.avatarStyle, avatarSeed: prof.avatarSeed };
|
|
1488
1569
|
}),
|
|
1489
1570
|
};
|
|
1490
|
-
session
|
|
1491
|
-
|
|
1492
|
-
ctx.sendToSession(session.localId, resumedMsg);
|
|
1571
|
+
persistDebateState(session);
|
|
1572
|
+
debateSendAndRecord(session, resumedMsg);
|
|
1493
1573
|
|
|
1494
1574
|
debate.turnInProgress = true;
|
|
1495
1575
|
debateMateProcessing(debate.moderatorId, true);
|
|
@@ -1531,15 +1611,17 @@ function attachDebate(ctx) {
|
|
|
1531
1611
|
moderatorContext += "---\n";
|
|
1532
1612
|
|
|
1533
1613
|
var _modMate3 = matesModule.getMate(mateCtx, debate.moderatorId);
|
|
1614
|
+
var resumedModeratorModel = participantModel(debate, debate.moderatorId);
|
|
1534
1615
|
ctx.sdk.createMentionSession({
|
|
1535
|
-
vendor: _modMate3 ? _modMate3.vendor : null,
|
|
1616
|
+
vendor: resumedModeratorModel ? resumedModeratorModel.vendor : (_modMate3 ? _modMate3.vendor : null),
|
|
1617
|
+
model: resumedModeratorModel ? resumedModeratorModel.model : undefined,
|
|
1536
1618
|
linuxUser: mateCtx.linuxUser || undefined,
|
|
1537
1619
|
claudeMd: claudeMd,
|
|
1538
1620
|
initialContext: moderatorContext,
|
|
1539
1621
|
initialMessage: resumePrompt,
|
|
1540
1622
|
onActivity: function (activity) {
|
|
1541
1623
|
if (session._debate && session._debate.phase !== "ended") {
|
|
1542
|
-
|
|
1624
|
+
debateSendAndRecord(session, { type: "debate_activity", mateId: debate.moderatorId, activity: activity });
|
|
1543
1625
|
}
|
|
1544
1626
|
},
|
|
1545
1627
|
onDelta: function (delta) {
|
|
@@ -1554,7 +1636,7 @@ function attachDebate(ctx) {
|
|
|
1554
1636
|
console.error("[debate] Moderator resume error:", errMsg);
|
|
1555
1637
|
endDebate(session, "error");
|
|
1556
1638
|
},
|
|
1557
|
-
canUseTool: buildDebateToolHandler(session),
|
|
1639
|
+
canUseTool: buildDebateToolHandler(session, debate.moderatorId),
|
|
1558
1640
|
}).then(function (mentionSession) {
|
|
1559
1641
|
if (mentionSession) {
|
|
1560
1642
|
debate.moderatorSession = mentionSession;
|
|
@@ -1584,6 +1666,7 @@ function attachDebate(ctx) {
|
|
|
1584
1666
|
|
|
1585
1667
|
debate.phase = "ended";
|
|
1586
1668
|
debate.turnInProgress = false;
|
|
1669
|
+
if (session.homeDebatePlanning === true) session.homeDebatePhase = reason === "interrupted" ? "interrupted" : "ended";
|
|
1587
1670
|
persistDebateState(session);
|
|
1588
1671
|
|
|
1589
1672
|
// Clean up brief watcher if still active
|
|
@@ -1593,17 +1676,20 @@ function attachDebate(ctx) {
|
|
|
1593
1676
|
}
|
|
1594
1677
|
|
|
1595
1678
|
// Notify clients
|
|
1596
|
-
|
|
1679
|
+
debateSendAndRecord(session, {
|
|
1597
1680
|
type: "debate_ended",
|
|
1598
1681
|
reason: reason,
|
|
1599
1682
|
rounds: debate.round,
|
|
1600
1683
|
topic: debate.topic,
|
|
1601
1684
|
});
|
|
1602
1685
|
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1686
|
+
if (debate.homeClient && session.homeDebatePlanning !== true) {
|
|
1687
|
+
if (typeof ctx.unregisterHomeDebateClient === "function") ctx.unregisterHomeDebateClient(debate.homeClient);
|
|
1688
|
+
debate.homeClient._clayActiveSession = debate.homeClient._clayHomePreviousSessionId || null;
|
|
1689
|
+
debate.homeClient._clayHomePreviousSessionId = null;
|
|
1690
|
+
debate.homeClient._clayHomeDebateSlug = null;
|
|
1691
|
+
debate.homeClient = null;
|
|
1692
|
+
}
|
|
1607
1693
|
|
|
1608
1694
|
// Generate digests for all participants
|
|
1609
1695
|
digestDebateParticipant(session, debate.moderatorId, debate, "moderator");
|
|
@@ -1725,6 +1811,7 @@ function attachDebate(ctx) {
|
|
|
1725
1811
|
context: briefData.context || "",
|
|
1726
1812
|
specialRequests: briefData.specialRequests || null,
|
|
1727
1813
|
moderatorId: mateId,
|
|
1814
|
+
participantModels: Array.isArray(briefData.participantModels) ? briefData.participantModels : [],
|
|
1728
1815
|
panelists: (briefData.panelists || []).map(function (p) {
|
|
1729
1816
|
return { mateId: p.mateId, role: p.role || "", brief: p.brief || "" };
|
|
1730
1817
|
}),
|
|
@@ -1745,10 +1832,26 @@ function attachDebate(ctx) {
|
|
|
1745
1832
|
session._debate = debate;
|
|
1746
1833
|
|
|
1747
1834
|
console.log("[debate] MCP debate approved. Topic:", debate.topic, "debateId:", debateId);
|
|
1748
|
-
|
|
1835
|
+
var homeWs = ws && ws._homeChatTap && ws._homeChatTap.mateSlug === ctx.slug && ws._homeChatTap.sessionId === session.localId ? ws : null;
|
|
1836
|
+
startDebateLive(session, homeWs);
|
|
1749
1837
|
return { ok: true };
|
|
1750
1838
|
}
|
|
1751
1839
|
|
|
1840
|
+
function handleHomeControl(ws, msg, session) {
|
|
1841
|
+
if (!session || session.homeDebatePlanning !== true) return false;
|
|
1842
|
+
if (!session._debate && (msg.action === "conclude" || msg.action === "resume")) rebuildDebateState(session, ws);
|
|
1843
|
+
if (!session._debate) return false;
|
|
1844
|
+
if (msg.action === "hand_raise") handleDebateHandRaise(ws, session);
|
|
1845
|
+
else if (msg.action === "comment") handleDebateComment(ws, msg, session);
|
|
1846
|
+
else if (msg.action === "stop") return handleDebateStop(ws, session);
|
|
1847
|
+
else if (msg.action === "cancel_stop") return handleDebateCancelStop(ws, session);
|
|
1848
|
+
else if (msg.action === "conclude") handleDebateConcludeResponse(ws, { action: msg.response, text: msg.text || "" }, session);
|
|
1849
|
+
else if (msg.action === "resume") handleDebateConcludeResponse(ws, { action: "continue", text: msg.text || "" }, session);
|
|
1850
|
+
else if (msg.action === "user_floor") handleDebateUserFloorResponse(ws, msg, session);
|
|
1851
|
+
else return false;
|
|
1852
|
+
return true;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1752
1855
|
// --- Public API ---
|
|
1753
1856
|
|
|
1754
1857
|
return {
|
|
@@ -1762,6 +1865,7 @@ function attachDebate(ctx) {
|
|
|
1762
1865
|
restoreDebateState: restoreDebateState,
|
|
1763
1866
|
checkForDmDebateBrief: checkForDmDebateBrief,
|
|
1764
1867
|
handleMcpDebateApproval: handleMcpDebateApproval,
|
|
1868
|
+
handleHomeControl: handleHomeControl,
|
|
1765
1869
|
};
|
|
1766
1870
|
}
|
|
1767
1871
|
|