@cfio/cohort-sync 0.31.13 → 0.32.0

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,113 @@ 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 roundtable, standup, report-in, or panel response, FIRST use cohort_room_start_moderation_session(room_id, mode, objective, participant_names) to run it as a managed session, then drive it with cohort_room_advance_moderation_session; do not only name agents in prose.
12283
+ - Otherwise, use the cohort_room_message tool to post a reply in the Room. Do NOT just think silently and exit.
12284
+ - Reply in your own voice (see your persona in IDENTITY.md).
12285
+ - If the human asks for a roundtable, standup, report-in, or panel response, contribute your own concise update.
12286
+ - 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.
12287
+ - 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
12288
  var TOOLS_REFERENCE = `
12194
12289
  TOOLS: Use these \u2014 do NOT call the REST API directly.
12195
12290
  - cohort_comment(task_number, comment) \u2014 post a comment
12196
- - cohort_room_message(room_id, message) \u2014 post a message in a Cohort Room
12291
+ - 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
12292
+ - cohort_room_start_moderation_session(room_id, mode, objective, participant_names) \u2014 moderator only: start a managed round robin or Q&A session
12293
+ - cohort_room_advance_moderation_session(session_id, action, ...) \u2014 moderator only: advance, retry, skip, accept, followup, or complete the session
12294
+ - cohort_room_cancel_moderation_session(session_id, reason?) \u2014 moderator only: cancel an in-flight session
12295
+ - 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)
12296
+ - 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
12297
  - cohort_task(task_number) \u2014 fetch full task details + comments
12198
12298
  - cohort_transition(task_number, status) \u2014 change status
12199
12299
  - cohort_assign(task_number, assignee) \u2014 assign/unassign
12200
12300
  - cohort_context() \u2014 get your session briefing`;
12301
+ var HANDOFF_REQUEST_TERMS = [
12302
+ "round robin",
12303
+ "round-robin",
12304
+ "go around",
12305
+ "around the table",
12306
+ "whole team",
12307
+ "everyone",
12308
+ "all hands",
12309
+ "pass the buck",
12310
+ "pass the conch"
12311
+ ];
12312
+ var HANDOFF_TOPIC_TERMS = [
12313
+ "standup",
12314
+ "stand-up",
12315
+ "report in",
12316
+ "report-in",
12317
+ "panel"
12318
+ ];
12319
+ var HANDOFF_ACTION_TERMS = [
12320
+ "moderate",
12321
+ "run",
12322
+ "gather",
12323
+ "ask"
12324
+ ];
12201
12325
  function sanitizePreview(raw) {
12202
12326
  return raw.replace(/<\/?user_comment>/gi, "");
12203
12327
  }
12328
+ function isHumanHandoffRequest(n) {
12329
+ if (n.actorType !== "human") {
12330
+ return false;
12331
+ }
12332
+ const preview = (n.preview ?? "").toLowerCase();
12333
+ if (HANDOFF_REQUEST_TERMS.some((term) => preview.includes(term))) {
12334
+ return true;
12335
+ }
12336
+ const hasTopic = HANDOFF_TOPIC_TERMS.some((term) => preview.includes(term));
12337
+ const hasAction = HANDOFF_ACTION_TERMS.some((term) => preview.includes(term));
12338
+ return hasTopic && hasAction;
12339
+ }
12340
+ function roomMessageCta(n) {
12341
+ const roomId = n.roomId ?? "unknown";
12342
+ if (n.moderationContext != null && renderModerationContext(n.moderationContext) !== "") {
12343
+ return "Follow the MODERATION SESSION block in this message \u2014 it is authoritative.";
12344
+ }
12345
+ if (isHumanHandoffRequest(n)) {
12346
+ 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.`;
12347
+ }
12348
+ if (isAgentReplyToModerator(n)) {
12349
+ const actor = n.actorName ?? "the agent";
12350
+ 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.`;
12351
+ }
12352
+ return `Reply in the Room if you can help. Use the cohort_room_message tool (roomId: ${roomId}).`;
12353
+ }
12354
+ function isAgentReplyToModerator(n) {
12355
+ if (n.actorType !== "agent") {
12356
+ return false;
12357
+ }
12358
+ const actor = (n.actorName ?? "").trim().toLowerCase();
12359
+ const recipient = (n.recipientAgent ?? "").trim().toLowerCase();
12360
+ const preview = (n.preview ?? "").toLowerCase();
12361
+ if (["please ", "passing the buck to you", "pass the buck to you"].some((term) => preview.includes(term))) {
12362
+ return false;
12363
+ }
12364
+ return Boolean(actor && recipient && actor !== recipient);
12365
+ }
12366
+ function renderModerationContext(ctx) {
12367
+ if (ctx.version !== 1) return "";
12368
+ const expected = ctx.expectedAgentNames.length > 0 ? ctx.expectedAgentNames.join(", ") : "(none)";
12369
+ const lines = [
12370
+ `[MODERATION SESSION ${ctx.sessionId}]`,
12371
+ `Mode: ${ctx.mode} | Status: ${ctx.status} | Auto-advance: ${ctx.autoAdvance ? "on" : "off"} | Queued behind: ${ctx.queuedCount}`,
12372
+ `Objective: ${ctx.objective}`,
12373
+ `Sequence: ${ctx.sequenceAgentNames.join(" -> ")} (cursor ${ctx.cursor}/${ctx.sequenceAgentNames.length})`,
12374
+ `Expected responder(s): ${expected}`,
12375
+ `Last event: ${ctx.lastEvent}`,
12376
+ `NEXT ACTION: ${ctx.nextActionHint}`,
12377
+ "Do NOT post commentary instead of advancing. Advance or complete via the session tools."
12378
+ ];
12379
+ if (ctx.respondTurnId) {
12380
+ lines.push(
12381
+ `To reply for this turn, call cohort_room_message(room_id: ${ctx.roomId}, message: <your reply>, turn_id: "${ctx.respondTurnId}").`
12382
+ );
12383
+ }
12384
+ lines.push("[/MODERATION SESSION]");
12385
+ return lines.join("\n");
12386
+ }
12204
12387
  function buildNotificationMessage(n) {
12205
12388
  let header;
12206
12389
  let cta;
@@ -12208,7 +12391,7 @@ function buildNotificationMessage(n) {
12208
12391
  case "room_message":
12209
12392
  header = `New message in Room "${n.roomName ?? n.roomId ?? "Room"}"
12210
12393
  From: ${n.actorName}`;
12211
- cta = `Reply in the Room if you can help. Use the cohort_room_message tool (roomId: ${n.roomId ?? "unknown"}).`;
12394
+ cta = roomMessageCta(n);
12212
12395
  break;
12213
12396
  case "comment":
12214
12397
  if (n.isMentioned) {
@@ -12257,7 +12440,13 @@ Comment: "${n.preview}"`;
12257
12440
  Scope: ${truncated}`;
12258
12441
  }
12259
12442
  let prompt;
12260
- if (n.type === "comment" && n.isMentioned || n.type === "room_message") {
12443
+ if (n.type === "room_message") {
12444
+ const moderationBlock = n.moderationContext != null ? renderModerationContext(n.moderationContext) : "";
12445
+ const preamble = moderationBlock || n.behavioralPrompt;
12446
+ prompt = preamble ? `${preamble}
12447
+
12448
+ ${ROOM_MESSAGE_RESPONSE_PROMPT}` : ROOM_MESSAGE_RESPONSE_PROMPT;
12449
+ } else if (n.type === "comment" && n.isMentioned) {
12261
12450
  prompt = n.behavioralPrompt ? `${n.behavioralPrompt}
12262
12451
 
12263
12452
  ${ATMENTION_RESPONSE_PROMPT}` : ATMENTION_RESPONSE_PROMPT;
@@ -13801,7 +13990,7 @@ function dumpEvent(event) {
13801
13990
  function positiveNumber(value) {
13802
13991
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
13803
13992
  }
13804
- var PLUGIN_VERSION = true ? "0.31.13" : "unknown";
13993
+ var PLUGIN_VERSION = true ? "0.32.0" : "unknown";
13805
13994
  function resolveGatewayToken(api) {
13806
13995
  const token2 = api.config?.gateway?.auth?.token;
13807
13996
  return typeof token2 === "string" ? token2 : null;
@@ -14939,7 +15128,8 @@ Do not attempt more comments until tomorrow.`);
14939
15128
  description: "Post a message in a Cohort Room. Use this to reply when you are participating in a Room chat.",
14940
15129
  parameters: Type.Object({
14941
15130
  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" })
15131
+ message: Type.String({ description: "Message text to post in the Room" }),
15132
+ turn_id: Type.Optional(Type.String({ description: "Moderation turn id to attribute this reply to (echo from your prompt)" }))
14943
15133
  }),
14944
15134
  async execute(_toolCallId, params) {
14945
15135
  const rt = getToolRuntime();
@@ -14950,7 +15140,8 @@ Do not attempt more comments until tomorrow.`);
14950
15140
  const result = await callAddRoomMessageFromPlugin(rt.apiKey, {
14951
15141
  roomId: params.room_id,
14952
15142
  agentName,
14953
- content: params.message
15143
+ content: params.message,
15144
+ ...params.turn_id !== void 0 ? { turnId: params.turn_id } : {}
14954
15145
  });
14955
15146
  return textResult(`Message posted to Room ${params.room_id}.`, result);
14956
15147
  }
@@ -15012,6 +15203,126 @@ Do not attempt more comments until tomorrow.`);
15012
15203
  }
15013
15204
  };
15014
15205
  });
15206
+ api.registerTool((toolCtx) => {
15207
+ const agentId = toolCtx.agentId ?? "main";
15208
+ return {
15209
+ name: "cohort_room_start_moderation_session",
15210
+ label: "cohort_room_start_moderation_session",
15211
+ description: "Start a managed moderation session in a Cohort Room. This is THE way to run round robins and moderated Q&A as the Room moderator: the backend prompts each participant in turn, tracks who responded, and tells you when to advance. 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.",
15212
+ parameters: Type.Object({
15213
+ room_id: Type.String({ description: "Room ID supplied by Cohort, e.g. rooms:abc123" }),
15214
+ mode: Type.Union([
15215
+ Type.Literal("round_robin"),
15216
+ Type.Literal("moderated_qna")
15217
+ ], { description: 'Session mode: "round_robin" (each participant responds in turn) or "moderated_qna" (one participant answers a question)' }),
15218
+ objective: Type.String({ description: "One-line objective for the session, e.g. 'Daily standup: blockers and progress'" }),
15219
+ participant_names: Type.Array(Type.String(), { description: "Cohort agent names to include, in speaking order" }),
15220
+ question_text: Type.Optional(Type.String({ description: "moderated_qna only: the question to ask the participant" })),
15221
+ auto_advance: Type.Optional(Type.Boolean({ description: "round_robin only: automatically prompt the next participant after each matched response" }))
15222
+ }),
15223
+ async execute(_toolCallId, params) {
15224
+ const rt = getToolRuntime();
15225
+ if (!rt.isReady) {
15226
+ return textResult("cohort_room_start_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15227
+ }
15228
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15229
+ try {
15230
+ const result = await callStartModerationSessionFromPlugin(rt.apiKey, {
15231
+ roomId: params.room_id,
15232
+ moderatorAgentName,
15233
+ mode: params.mode,
15234
+ objective: params.objective,
15235
+ participantAgentNames: params.participant_names,
15236
+ ...params.question_text !== void 0 ? { questionText: params.question_text } : {},
15237
+ ...params.auto_advance !== void 0 ? { autoAdvance: params.auto_advance } : {}
15238
+ });
15239
+ return textResult(result.stateBlock, result);
15240
+ } catch (err) {
15241
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15242
+ return textResult(`Failed to start moderation session: ${msg}`);
15243
+ }
15244
+ }
15245
+ };
15246
+ });
15247
+ api.registerTool((toolCtx) => {
15248
+ const agentId = toolCtx.agentId ?? "main";
15249
+ return {
15250
+ name: "cohort_room_advance_moderation_session",
15251
+ label: "cohort_room_advance_moderation_session",
15252
+ description: 'Advance a moderation session you are running: "next" prompts the next participant, "retry"/"skip"/"accept" resolve a mismatched turn, "followup" asks a target a follow-up question, and "complete" ends the session. 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.',
15253
+ parameters: Type.Object({
15254
+ session_id: Type.String({ description: "Moderation session ID returned by cohort_room_start_moderation_session" }),
15255
+ action: Type.Union([
15256
+ Type.Literal("next"),
15257
+ Type.Literal("retry"),
15258
+ Type.Literal("skip"),
15259
+ Type.Literal("accept"),
15260
+ Type.Literal("followup"),
15261
+ Type.Literal("complete")
15262
+ ], { description: "next = prompt the next 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 a follow-up question (Q&A only); complete = finish the session (pass summary/decisions/proposed_tasks to create the recap)." }),
15263
+ prompt: Type.Optional(Type.String({ description: "Custom prompt for the turn (next/retry/followup)" })),
15264
+ target_agent_name: Type.Optional(Type.String({ description: "followup only: the agent to ask" })),
15265
+ summary: Type.Optional(Type.String({ description: "complete only: session recap summary" })),
15266
+ decisions: Type.Optional(Type.Array(Type.String(), { description: "complete only: decisions reached" })),
15267
+ proposed_tasks: Type.Optional(Type.Array(Type.String(), { description: "complete only: proposed tasks for human approval" })),
15268
+ follow_ups: Type.Optional(Type.Array(Type.String(), { description: "complete only: follow-up items" }))
15269
+ }),
15270
+ async execute(_toolCallId, params) {
15271
+ const rt = getToolRuntime();
15272
+ if (!rt.isReady) {
15273
+ return textResult("cohort_room_advance_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15274
+ }
15275
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15276
+ try {
15277
+ const result = await callAdvanceModerationSessionFromPlugin(rt.apiKey, {
15278
+ sessionId: params.session_id,
15279
+ moderatorAgentName,
15280
+ action: params.action,
15281
+ ...params.prompt !== void 0 ? { prompt: params.prompt } : {},
15282
+ ...params.target_agent_name !== void 0 ? { targetAgentName: params.target_agent_name } : {},
15283
+ ...params.summary !== void 0 ? { summary: params.summary } : {},
15284
+ ...params.decisions !== void 0 ? { decisions: params.decisions } : {},
15285
+ ...params.proposed_tasks !== void 0 ? { proposedTasks: params.proposed_tasks } : {},
15286
+ ...params.follow_ups !== void 0 ? { followUps: params.follow_ups } : {}
15287
+ });
15288
+ return textResult(result.stateBlock, result);
15289
+ } catch (err) {
15290
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15291
+ return textResult(`Failed to advance moderation session: ${msg}`);
15292
+ }
15293
+ }
15294
+ };
15295
+ });
15296
+ api.registerTool((toolCtx) => {
15297
+ const agentId = toolCtx.agentId ?? "main";
15298
+ return {
15299
+ name: "cohort_room_cancel_moderation_session",
15300
+ label: "cohort_room_cancel_moderation_session",
15301
+ 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.",
15302
+ parameters: Type.Object({
15303
+ session_id: Type.String({ description: "Moderation session ID to cancel" }),
15304
+ reason: Type.Optional(Type.String({ description: "Short reason for canceling" }))
15305
+ }),
15306
+ async execute(_toolCallId, params) {
15307
+ const rt = getToolRuntime();
15308
+ if (!rt.isReady) {
15309
+ return textResult("cohort_room_cancel_moderation_session is not ready yet \u2014 the plugin is still starting up. Try again in a few seconds.");
15310
+ }
15311
+ const moderatorAgentName = rt.resolveAgentName(agentId);
15312
+ try {
15313
+ const result = await callCancelModerationSessionFromPlugin(rt.apiKey, {
15314
+ sessionId: params.session_id,
15315
+ moderatorAgentName,
15316
+ ...params.reason !== void 0 ? { reason: params.reason } : {}
15317
+ });
15318
+ return textResult(result.stateBlock, result);
15319
+ } catch (err) {
15320
+ const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
15321
+ return textResult(`Failed to cancel moderation session: ${msg}`);
15322
+ }
15323
+ }
15324
+ };
15325
+ });
15015
15326
  api.registerTool(() => {
15016
15327
  return {
15017
15328
  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.0"
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.0",
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.0",
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",