@cfio/cohort-sync 0.31.13 → 0.32.1

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/dist/index.js CHANGED
@@ -12000,6 +12000,9 @@ var failCommandRef = makeFunctionReference("gatewayCommands:failCommand");
12000
12000
  var getChannelsForPlugin = makeFunctionReference("cloudGatewayChannels:listForPlugin");
12001
12001
  var addCommentFromPluginRef = makeFunctionReference("comments:addCommentFromPlugin");
12002
12002
  var addRoomMessageFromPluginRef = makeFunctionReference("rooms:addMessageFromPlugin");
12003
+ var startModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:startFromPlugin");
12004
+ var advanceModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:advanceFromPlugin");
12005
+ var cancelModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:cancelFromPlugin");
12003
12006
  var promptAgentsFromPluginRef = makeFunctionReference("rooms:promptAgentsFromPlugin");
12004
12007
  var transitionFromPluginRef = makeFunctionReference("tasks:transitionFromPlugin");
12005
12008
  async function pushTelemetry(apiKey2, data) {
@@ -12119,7 +12122,91 @@ async function callAddRoomMessageFromPlugin(apiKey2, args) {
12119
12122
  apiKeyHash: hashApiKey(apiKey2),
12120
12123
  roomId: args.roomId,
12121
12124
  agentName: args.agentName,
12122
- body: args.content
12125
+ body: args.content,
12126
+ // Omit (not undefined) when absent — keeps the wire args clean.
12127
+ ...args.turnId !== void 0 ? { turnId: args.turnId } : {}
12128
+ });
12129
+ } catch (err) {
12130
+ if (isUnauthorizedError(err)) {
12131
+ tripAuthCircuit();
12132
+ }
12133
+ throw err;
12134
+ }
12135
+ }
12136
+ async function callStartModerationSessionFromPlugin(apiKey2, args) {
12137
+ if (authCircuitOpen) {
12138
+ throw new Error(
12139
+ 'cohort-sync: API key rejected \u2014 all outbound mutations disabled until gateway restart.\n 1. Create a new key at https://my.cohort.bot/settings/api-keys\n 2. Run: openclaw config set plugins.entries.cohort-sync.config.apiKey "ch_live_..."'
12140
+ );
12141
+ }
12142
+ const c = getClient();
12143
+ if (!c) {
12144
+ throw new Error("Convex client not initialized \u2014 subscription may not be active");
12145
+ }
12146
+ try {
12147
+ return await c.mutation(startModerationSessionFromPluginRef, {
12148
+ apiKeyHash: hashApiKey(apiKey2),
12149
+ roomId: args.roomId,
12150
+ moderatorAgentName: args.moderatorAgentName,
12151
+ mode: args.mode,
12152
+ objective: args.objective,
12153
+ participantAgentNames: args.participantAgentNames,
12154
+ ...args.questionText !== void 0 ? { questionText: args.questionText } : {},
12155
+ ...args.autoAdvance !== void 0 ? { autoAdvance: args.autoAdvance } : {}
12156
+ });
12157
+ } catch (err) {
12158
+ if (isUnauthorizedError(err)) {
12159
+ tripAuthCircuit();
12160
+ }
12161
+ throw err;
12162
+ }
12163
+ }
12164
+ async function callAdvanceModerationSessionFromPlugin(apiKey2, args) {
12165
+ if (authCircuitOpen) {
12166
+ throw new Error(
12167
+ 'cohort-sync: API key rejected \u2014 all outbound mutations disabled until gateway restart.\n 1. Create a new key at https://my.cohort.bot/settings/api-keys\n 2. Run: openclaw config set plugins.entries.cohort-sync.config.apiKey "ch_live_..."'
12168
+ );
12169
+ }
12170
+ const c = getClient();
12171
+ if (!c) {
12172
+ throw new Error("Convex client not initialized \u2014 subscription may not be active");
12173
+ }
12174
+ try {
12175
+ return await c.mutation(advanceModerationSessionFromPluginRef, {
12176
+ apiKeyHash: hashApiKey(apiKey2),
12177
+ sessionId: args.sessionId,
12178
+ moderatorAgentName: args.moderatorAgentName,
12179
+ action: args.action,
12180
+ ...args.prompt !== void 0 ? { prompt: args.prompt } : {},
12181
+ ...args.targetAgentName !== void 0 ? { targetAgentName: args.targetAgentName } : {},
12182
+ ...args.summary !== void 0 ? { summary: args.summary } : {},
12183
+ ...args.decisions !== void 0 ? { decisions: args.decisions } : {},
12184
+ ...args.proposedTasks !== void 0 ? { proposedTasks: args.proposedTasks } : {},
12185
+ ...args.followUps !== void 0 ? { followUps: args.followUps } : {}
12186
+ });
12187
+ } catch (err) {
12188
+ if (isUnauthorizedError(err)) {
12189
+ tripAuthCircuit();
12190
+ }
12191
+ throw err;
12192
+ }
12193
+ }
12194
+ async function callCancelModerationSessionFromPlugin(apiKey2, args) {
12195
+ if (authCircuitOpen) {
12196
+ throw new Error(
12197
+ 'cohort-sync: API key rejected \u2014 all outbound mutations disabled until gateway restart.\n 1. Create a new key at https://my.cohort.bot/settings/api-keys\n 2. Run: openclaw config set plugins.entries.cohort-sync.config.apiKey "ch_live_..."'
12198
+ );
12199
+ }
12200
+ const c = getClient();
12201
+ if (!c) {
12202
+ throw new Error("Convex client not initialized \u2014 subscription may not be active");
12203
+ }
12204
+ try {
12205
+ return await c.mutation(cancelModerationSessionFromPluginRef, {
12206
+ apiKeyHash: hashApiKey(apiKey2),
12207
+ sessionId: args.sessionId,
12208
+ moderatorAgentName: args.moderatorAgentName,
12209
+ ...args.reason !== void 0 ? { reason: args.reason } : {}
12123
12210
  });
12124
12211
  } catch (err) {
12125
12212
  if (isUnauthorizedError(err)) {
@@ -12190,17 +12277,134 @@ var ATMENTION_RESPONSE_PROMPT = `YOU WERE DIRECTLY @-MENTIONED. RESPOND.
12190
12277
  - If the mention is a question, answer it. If it's a request, acknowledge what you'll do (and then do it).
12191
12278
  - For coding requests, do not stop at local implementation; source scripts/agent-dev-env.sh, push your branch, open a PR, enable auto-merge, watch CI until green or red, confirm the PR merged, verify the production deploy with gh run watch, and then comment with the PR link plus verification evidence.
12192
12279
  - Do not stop because Vercel CLI is not authenticated; Cohort deploys through GitHub Actions after merge.`;
12280
+ var ROOM_MESSAGE_RESPONSE_PROMPT = `YOU WERE DIRECTLY ASKED IN A COHORT ROOM. RESPOND.
12281
+
12282
+ - If you are the Room moderator and a human asks for a question to be routed, FIRST use cohort_room_start_moderation_session with mode: "moderated_qna", one best participant, and question_text; use cohort_room_advance_moderation_session(action: "followup") for additional experts one at a time, then confirm with the asker before complete.
12283
+ - If you are the Room moderator and a human asks for a roundtable, standup, report-in, or panel response, FIRST use cohort_room_start_moderation_session with mode: "round_robin" to run it as a managed session, then drive it with cohort_room_advance_moderation_session; do not only name agents in prose.
12284
+ - Otherwise, use the cohort_room_message tool to post a reply in the Room. Do NOT just think silently and exit.
12285
+ - Reply in your own voice (see your persona in IDENTITY.md).
12286
+ - If the human asks for an answer, answer it. If the human asks for a roundtable, standup, report-in, or panel response, contribute your own concise update.
12287
+ - If the moderator asks you to answer, answer. If another agent asks for your report, provide it. If your prompt includes a turn_id, echo it in cohort_room_message.
12288
+ - A brief, honest reply is better than no reply. If you genuinely have nothing to add, say so explicitly in the Room \u2014 don't go silent.`;
12193
12289
  var TOOLS_REFERENCE = `
12194
12290
  TOOLS: Use these \u2014 do NOT call the REST API directly.
12195
12291
  - cohort_comment(task_number, comment) \u2014 post a comment
12196
- - cohort_room_message(room_id, message) \u2014 post a message in a Cohort Room
12292
+ - cohort_room_message(room_id, message, turn_id?) \u2014 post a message in a Cohort Room; pass turn_id when your prompt included one so the reply is attributed to that moderation turn
12293
+ - cohort_room_start_moderation_session(room_id, mode, objective, participant_names) \u2014 moderator only: start a managed session; round_robin = ask every participant to report in, moderated_qna = route a question to one selected agent
12294
+ - cohort_room_advance_moderation_session(session_id, action, ...) \u2014 moderator only: advance, retry, skip, accept, followup, or complete the session; followup asks one additional Q&A expert after the first answer
12295
+ - cohort_room_cancel_moderation_session(session_id, reason?) \u2014 moderator only: cancel an in-flight session
12296
+ - cohort_room_prompt_agent(roomId, agentName, prompt) \u2014 moderator only, low-level: ask one Room agent to respond (prefer moderation sessions for multi-step workflows)
12297
+ - cohort_room_prompt_agents(roomId, agentNames, prompt) \u2014 moderator only, low-level: ask multiple Room agents to respond (prefer moderation sessions for multi-step workflows)
12197
12298
  - cohort_task(task_number) \u2014 fetch full task details + comments
12198
12299
  - cohort_transition(task_number, status) \u2014 change status
12199
12300
  - cohort_assign(task_number, assignee) \u2014 assign/unassign
12200
12301
  - cohort_context() \u2014 get your session briefing`;
12302
+ var HANDOFF_REQUEST_TERMS = [
12303
+ "round robin",
12304
+ "round-robin",
12305
+ "go around",
12306
+ "around the table",
12307
+ "whole team",
12308
+ "everyone",
12309
+ "all hands",
12310
+ "pass the buck",
12311
+ "pass the conch"
12312
+ ];
12313
+ var HANDOFF_TOPIC_TERMS = [
12314
+ "standup",
12315
+ "stand-up",
12316
+ "report in",
12317
+ "report-in",
12318
+ "panel"
12319
+ ];
12320
+ var HANDOFF_ACTION_TERMS = [
12321
+ "moderate",
12322
+ "run",
12323
+ "gather",
12324
+ "ask"
12325
+ ];
12326
+ var QUESTION_ROUTING_TERMS = [
12327
+ "question for the team",
12328
+ "route it",
12329
+ "route this",
12330
+ "ask whoever",
12331
+ "whoever's best suited",
12332
+ "whoever is best suited",
12333
+ "who's best suited",
12334
+ "who is best suited"
12335
+ ];
12201
12336
  function sanitizePreview(raw) {
12202
12337
  return raw.replace(/<\/?user_comment>/gi, "");
12203
12338
  }
12339
+ function isHumanHandoffRequest(n) {
12340
+ if (n.actorType !== "human") {
12341
+ return false;
12342
+ }
12343
+ const preview = (n.preview ?? "").toLowerCase();
12344
+ if (HANDOFF_REQUEST_TERMS.some((term) => preview.includes(term))) {
12345
+ return true;
12346
+ }
12347
+ const hasTopic = HANDOFF_TOPIC_TERMS.some((term) => preview.includes(term));
12348
+ const hasAction = HANDOFF_ACTION_TERMS.some((term) => preview.includes(term));
12349
+ return hasTopic && hasAction;
12350
+ }
12351
+ function isHumanQuestionRoutingRequest(n) {
12352
+ if (n.actorType !== "human") {
12353
+ return false;
12354
+ }
12355
+ const preview = (n.preview ?? "").toLowerCase();
12356
+ return QUESTION_ROUTING_TERMS.some((term) => preview.includes(term)) || /\bhave\s+[a-z][a-z0-9_-]*\s+answer\b/.test(preview);
12357
+ }
12358
+ function roomMessageCta(n) {
12359
+ const roomId = n.roomId ?? "unknown";
12360
+ if (n.moderationContext != null && renderModerationContext(n.moderationContext) !== "") {
12361
+ return "Follow the MODERATION SESSION block in this message \u2014 it is authoritative.";
12362
+ }
12363
+ if (isHumanQuestionRoutingRequest(n)) {
12364
+ return `You are moderating a Room Q&A. FIRST use cohort_room_start_moderation_session(room_id: ${roomId}, mode: "moderated_qna", objective: <one-line objective>, participant_names: [<single best agent>], question_text: <the question>) to route the question to one selected expert. If more expertise is needed after the answer, use cohort_room_advance_moderation_session(action: "followup", target_agent_name: <next expert>, prompt: <follow-up question>) for one additional expert at a time (advance(action: "followup")). Then ask the asker whether the answer resolves the question before complete.`;
12365
+ }
12366
+ if (isHumanHandoffRequest(n)) {
12367
+ return `You are moderating a Room round robin. FIRST use cohort_room_start_moderation_session(room_id: ${roomId}, mode: "round_robin", objective: <one-line objective>, participant_names: [<agents>]) to run it as a managed moderation session. Do NOT only post @agent prose and do NOT hand-roll turn-taking with cohort_room_prompt_agent. The session prompts each participant for you and tells you when to advance; finish with cohort_room_advance_moderation_session(action: "complete") to record the outcomes.`;
12368
+ }
12369
+ if (isAgentReplyToModerator(n)) {
12370
+ const actor = n.actorName ?? "the agent";
12371
+ return `If you are the Room moderator continuing a round robin, The <user_comment> preview is the agent's actual Room reply from ${actor}. Check whether the From: agent is the expected participant. If correct and the round robin has more participants, FIRST call cohort_room_prompt_agent for the next participant. If wrong, prompt the correct agent. Only consolidate when the requested sequence is complete. Do NOT stop after posting a commentary message.`;
12372
+ }
12373
+ return `Reply in the Room if you can help. Use the cohort_room_message tool (roomId: ${roomId}).`;
12374
+ }
12375
+ function isAgentReplyToModerator(n) {
12376
+ if (n.actorType !== "agent") {
12377
+ return false;
12378
+ }
12379
+ const actor = (n.actorName ?? "").trim().toLowerCase();
12380
+ const recipient = (n.recipientAgent ?? "").trim().toLowerCase();
12381
+ const preview = (n.preview ?? "").toLowerCase();
12382
+ if (["please ", "passing the buck to you", "pass the buck to you"].some((term) => preview.includes(term))) {
12383
+ return false;
12384
+ }
12385
+ return Boolean(actor && recipient && actor !== recipient);
12386
+ }
12387
+ function renderModerationContext(ctx) {
12388
+ if (ctx.version !== 1) return "";
12389
+ const expected = ctx.expectedAgentNames.length > 0 ? ctx.expectedAgentNames.join(", ") : "(none)";
12390
+ const lines = [
12391
+ `[MODERATION SESSION ${ctx.sessionId}]`,
12392
+ `Mode: ${ctx.mode} | Status: ${ctx.status} | Auto-advance: ${ctx.autoAdvance ? "on" : "off"} | Queued behind: ${ctx.queuedCount}`,
12393
+ `Objective: ${ctx.objective}`,
12394
+ `Sequence: ${ctx.sequenceAgentNames.join(" -> ")} (cursor ${ctx.cursor}/${ctx.sequenceAgentNames.length})`,
12395
+ `Expected responder(s): ${expected}`,
12396
+ `Last event: ${ctx.lastEvent}`,
12397
+ `NEXT ACTION: ${ctx.nextActionHint}`,
12398
+ "Do NOT post commentary instead of advancing. Advance or complete via the session tools."
12399
+ ];
12400
+ if (ctx.respondTurnId) {
12401
+ lines.push(
12402
+ `To reply for this turn, call cohort_room_message(room_id: ${ctx.roomId}, message: <your reply>, turn_id: "${ctx.respondTurnId}").`
12403
+ );
12404
+ }
12405
+ lines.push("[/MODERATION SESSION]");
12406
+ return lines.join("\n");
12407
+ }
12204
12408
  function buildNotificationMessage(n) {
12205
12409
  let header;
12206
12410
  let cta;
@@ -12208,7 +12412,7 @@ function buildNotificationMessage(n) {
12208
12412
  case "room_message":
12209
12413
  header = `New message in Room "${n.roomName ?? n.roomId ?? "Room"}"
12210
12414
  From: ${n.actorName}`;
12211
- cta = `Reply in the Room if you can help. Use the cohort_room_message tool (roomId: ${n.roomId ?? "unknown"}).`;
12415
+ cta = roomMessageCta(n);
12212
12416
  break;
12213
12417
  case "comment":
12214
12418
  if (n.isMentioned) {
@@ -12257,7 +12461,13 @@ Comment: "${n.preview}"`;
12257
12461
  Scope: ${truncated}`;
12258
12462
  }
12259
12463
  let prompt;
12260
- if (n.type === "comment" && n.isMentioned || n.type === "room_message") {
12464
+ if (n.type === "room_message") {
12465
+ const moderationBlock = n.moderationContext != null ? renderModerationContext(n.moderationContext) : "";
12466
+ const preamble = moderationBlock || n.behavioralPrompt;
12467
+ prompt = preamble ? `${preamble}
12468
+
12469
+ ${ROOM_MESSAGE_RESPONSE_PROMPT}` : ROOM_MESSAGE_RESPONSE_PROMPT;
12470
+ } else if (n.type === "comment" && n.isMentioned) {
12261
12471
  prompt = n.behavioralPrompt ? `${n.behavioralPrompt}
12262
12472
 
12263
12473
  ${ATMENTION_RESPONSE_PROMPT}` : ATMENTION_RESPONSE_PROMPT;
@@ -13801,7 +14011,7 @@ function dumpEvent(event) {
13801
14011
  function positiveNumber(value) {
13802
14012
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
13803
14013
  }
13804
- var PLUGIN_VERSION = true ? "0.31.13" : "unknown";
14014
+ var PLUGIN_VERSION = true ? "0.32.1" : "unknown";
13805
14015
  function resolveGatewayToken(api) {
13806
14016
  const token2 = api.config?.gateway?.auth?.token;
13807
14017
  return typeof token2 === "string" ? token2 : null;
@@ -14939,7 +15149,8 @@ Do not attempt more comments until tomorrow.`);
14939
15149
  description: "Post a message in a Cohort Room. Use this to reply when you are participating in a Room chat.",
14940
15150
  parameters: Type.Object({
14941
15151
  room_id: Type.String({ description: "Room ID supplied by Cohort, e.g. rooms:abc123" }),
14942
- message: Type.String({ description: "Message text to post in the Room" })
15152
+ message: Type.String({ description: "Message text to post in the Room" }),
15153
+ turn_id: Type.Optional(Type.String({ description: "Moderation turn id to attribute this reply to (echo from your prompt)" }))
14943
15154
  }),
14944
15155
  async execute(_toolCallId, params) {
14945
15156
  const rt = getToolRuntime();
@@ -14950,7 +15161,8 @@ Do not attempt more comments until tomorrow.`);
14950
15161
  const result = await callAddRoomMessageFromPlugin(rt.apiKey, {
14951
15162
  roomId: params.room_id,
14952
15163
  agentName,
14953
- content: params.message
15164
+ content: params.message,
15165
+ ...params.turn_id !== void 0 ? { turnId: params.turn_id } : {}
14954
15166
  });
14955
15167
  return textResult(`Message posted to Room ${params.room_id}.`, result);
14956
15168
  }
@@ -15012,6 +15224,126 @@ Do not attempt more comments until tomorrow.`);
15012
15224
  }
15013
15225
  };
15014
15226
  });
15227
+ api.registerTool((toolCtx) => {
15228
+ const agentId = toolCtx.agentId ?? "main";
15229
+ return {
15230
+ name: "cohort_room_start_moderation_session",
15231
+ label: "cohort_room_start_moderation_session",
15232
+ description: 'Start a managed moderation session in a Cohort Room. Use round_robin = ask every participant to report in; use moderated_qna = route a question to one selected agent, wait for the answer, ask the asker whether it resolves the question, then complete. For multiple experts in Q&A, start with one best agent and use action: "followup" for additional experts one at a time. Returns the session state block. The returned block includes the session_id \u2014 pass it to cohort_room_advance_moderation_session for every subsequent action.',
15233
+ parameters: Type.Object({
15234
+ room_id: Type.String({ description: "Room ID supplied by Cohort, e.g. rooms:abc123" }),
15235
+ mode: Type.Union([
15236
+ Type.Literal("round_robin"),
15237
+ Type.Literal("moderated_qna")
15238
+ ], { description: 'Session mode: "round_robin" means every participant reports in; "moderated_qna" means one selected participant answers a question, with serial followups for more experts.' }),
15239
+ objective: Type.String({ description: "One-line objective for the session, e.g. 'Daily standup: blockers and progress'" }),
15240
+ participant_names: Type.Array(Type.String(), { description: "Cohort agent names to include, in speaking order; moderated_qna should include exactly one best agent" }),
15241
+ question_text: Type.Optional(Type.String({ description: "moderated_qna only: the question to ask the selected participant" })),
15242
+ auto_advance: Type.Optional(Type.Boolean({ description: "round_robin only: automatically prompt the next participant after each matched response" }))
15243
+ }),
15244
+ async execute(_toolCallId, params) {
15245
+ const rt = getToolRuntime();
15246
+ if (!rt.isReady) {
15247
+ return textResult("cohort_room_start_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15248
+ }
15249
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15250
+ try {
15251
+ const result = await callStartModerationSessionFromPlugin(rt.apiKey, {
15252
+ roomId: params.room_id,
15253
+ moderatorAgentName,
15254
+ mode: params.mode,
15255
+ objective: params.objective,
15256
+ participantAgentNames: params.participant_names,
15257
+ ...params.question_text !== void 0 ? { questionText: params.question_text } : {},
15258
+ ...params.auto_advance !== void 0 ? { autoAdvance: params.auto_advance } : {}
15259
+ });
15260
+ return textResult(result.stateBlock, result);
15261
+ } catch (err) {
15262
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15263
+ return textResult(`Failed to start moderation session: ${msg}`);
15264
+ }
15265
+ }
15266
+ };
15267
+ });
15268
+ api.registerTool((toolCtx) => {
15269
+ const agentId = toolCtx.agentId ?? "main";
15270
+ return {
15271
+ name: "cohort_room_advance_moderation_session",
15272
+ label: "cohort_room_advance_moderation_session",
15273
+ description: 'Advance a moderation session you are running: "next" prompts the next round-robin participant, "retry"/"skip"/"accept" resolve a mismatched turn, followup asks one additional Q&A expert after the first answer, and "complete" ends the session. For moderated_qna, confirm with the asker before complete. Outcomes passed with action "complete" (summary, decisions, proposed_tasks, follow_ups) become the session recap; proposed_tasks surface for human approval. Returns the updated session state block.',
15274
+ parameters: Type.Object({
15275
+ session_id: Type.String({ description: "Moderation session ID returned by cohort_room_start_moderation_session" }),
15276
+ action: Type.Union([
15277
+ Type.Literal("next"),
15278
+ Type.Literal("retry"),
15279
+ Type.Literal("skip"),
15280
+ Type.Literal("accept"),
15281
+ Type.Literal("followup"),
15282
+ Type.Literal("complete")
15283
+ ], { description: "next = prompt the next round-robin participant (from waiting); retry = re-prompt the same agent; skip = skip the expected agent and move on; accept = accept an out-of-order reply as the response; followup = route one additional Q&A question to one target agent; complete = finish after asker confirmation when in Q&A (pass summary/decisions/proposed_tasks to create the recap)." }),
15284
+ prompt: Type.Optional(Type.String({ description: "Custom prompt for the turn (next/retry/followup)" })),
15285
+ target_agent_name: Type.Optional(Type.String({ description: "followup only: the agent to ask" })),
15286
+ summary: Type.Optional(Type.String({ description: "complete only: session recap summary" })),
15287
+ decisions: Type.Optional(Type.Array(Type.String(), { description: "complete only: decisions reached" })),
15288
+ proposed_tasks: Type.Optional(Type.Array(Type.String(), { description: "complete only: proposed tasks for human approval" })),
15289
+ follow_ups: Type.Optional(Type.Array(Type.String(), { description: "complete only: follow-up items" }))
15290
+ }),
15291
+ async execute(_toolCallId, params) {
15292
+ const rt = getToolRuntime();
15293
+ if (!rt.isReady) {
15294
+ return textResult("cohort_room_advance_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15295
+ }
15296
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15297
+ try {
15298
+ const result = await callAdvanceModerationSessionFromPlugin(rt.apiKey, {
15299
+ sessionId: params.session_id,
15300
+ moderatorAgentName,
15301
+ action: params.action,
15302
+ ...params.prompt !== void 0 ? { prompt: params.prompt } : {},
15303
+ ...params.target_agent_name !== void 0 ? { targetAgentName: params.target_agent_name } : {},
15304
+ ...params.summary !== void 0 ? { summary: params.summary } : {},
15305
+ ...params.decisions !== void 0 ? { decisions: params.decisions } : {},
15306
+ ...params.proposed_tasks !== void 0 ? { proposedTasks: params.proposed_tasks } : {},
15307
+ ...params.follow_ups !== void 0 ? { followUps: params.follow_ups } : {}
15308
+ });
15309
+ return textResult(result.stateBlock, result);
15310
+ } catch (err) {
15311
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15312
+ return textResult(`Failed to advance moderation session: ${msg}`);
15313
+ }
15314
+ }
15315
+ };
15316
+ });
15317
+ api.registerTool((toolCtx) => {
15318
+ const agentId = toolCtx.agentId ?? "main";
15319
+ return {
15320
+ name: "cohort_room_cancel_moderation_session",
15321
+ label: "cohort_room_cancel_moderation_session",
15322
+ description: "Cancel a moderation session you are running (e.g. superseded, no longer needed). Only valid while the session is queued, active, or waiting \u2014 completed/failed sessions cannot be canceled. Returns the final session state block.",
15323
+ parameters: Type.Object({
15324
+ session_id: Type.String({ description: "Moderation session ID to cancel" }),
15325
+ reason: Type.Optional(Type.String({ description: "Short reason for canceling" }))
15326
+ }),
15327
+ async execute(_toolCallId, params) {
15328
+ const rt = getToolRuntime();
15329
+ if (!rt.isReady) {
15330
+ return textResult("cohort_room_cancel_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15331
+ }
15332
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15333
+ try {
15334
+ const result = await callCancelModerationSessionFromPlugin(rt.apiKey, {
15335
+ sessionId: params.session_id,
15336
+ moderatorAgentName,
15337
+ ...params.reason !== void 0 ? { reason: params.reason } : {}
15338
+ });
15339
+ return textResult(result.stateBlock, result);
15340
+ } catch (err) {
15341
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15342
+ return textResult(`Failed to cancel moderation session: ${msg}`);
15343
+ }
15344
+ }
15345
+ };
15346
+ });
15015
15347
  api.registerTool(() => {
15016
15348
  return {
15017
15349
  name: "cohort_context",
@@ -14,6 +14,9 @@
14
14
  "cohort_room_message",
15
15
  "cohort_room_prompt_agent",
16
16
  "cohort_room_prompt_agents",
17
+ "cohort_room_start_moderation_session",
18
+ "cohort_room_advance_moderation_session",
19
+ "cohort_room_cancel_moderation_session",
17
20
  "cohort_context",
18
21
  "cohort_briefing_context",
19
22
  "cohort_briefing",
@@ -77,5 +80,5 @@
77
80
  }
78
81
  }
79
82
  },
80
- "version": "0.31.13"
83
+ "version": "0.32.1"
81
84
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.31.13",
3
+ "version": "0.32.1",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -12,6 +12,9 @@
12
12
  "cohort_room_message",
13
13
  "cohort_room_prompt_agent",
14
14
  "cohort_room_prompt_agents",
15
+ "cohort_room_start_moderation_session",
16
+ "cohort_room_advance_moderation_session",
17
+ "cohort_room_cancel_moderation_session",
15
18
  "cohort_context",
16
19
  "cohort_briefing_context",
17
20
  "cohort_briefing",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.31.13",
3
+ "version": "0.32.1",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.cohort.bot/gateway",