@cfio/cohort-sync 0.32.1 → 0.33.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 +416 -8
- package/dist/openclaw.plugin.json +3 -1
- package/dist/package.json +1 -1
- package/openclaw.plugin.json +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2615,6 +2615,9 @@ __export(type_exports2, {
|
|
|
2615
2615
|
// ../../node_modules/.pnpm/@sinclair+typebox@0.34.48/node_modules/@sinclair/typebox/build/esm/type/type/index.mjs
|
|
2616
2616
|
var Type = type_exports2;
|
|
2617
2617
|
|
|
2618
|
+
// index.ts
|
|
2619
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
2620
|
+
|
|
2618
2621
|
// src/hooks.ts
|
|
2619
2622
|
import fs2 from "node:fs";
|
|
2620
2623
|
import os2 from "node:os";
|
|
@@ -12000,6 +12003,8 @@ var failCommandRef = makeFunctionReference("gatewayCommands:failCommand");
|
|
|
12000
12003
|
var getChannelsForPlugin = makeFunctionReference("cloudGatewayChannels:listForPlugin");
|
|
12001
12004
|
var addCommentFromPluginRef = makeFunctionReference("comments:addCommentFromPlugin");
|
|
12002
12005
|
var addRoomMessageFromPluginRef = makeFunctionReference("rooms:addMessageFromPlugin");
|
|
12006
|
+
var generateWireUploadUrlFromPluginRef = makeFunctionReference("wire:generateUploadUrl");
|
|
12007
|
+
var publishWireFromPluginRef = makeFunctionReference("wire:publish");
|
|
12003
12008
|
var startModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:startFromPlugin");
|
|
12004
12009
|
var advanceModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:advanceFromPlugin");
|
|
12005
12010
|
var cancelModerationSessionFromPluginRef = makeFunctionReference("moderationSessions:cancelFromPlugin");
|
|
@@ -12133,6 +12138,60 @@ async function callAddRoomMessageFromPlugin(apiKey2, args) {
|
|
|
12133
12138
|
throw err;
|
|
12134
12139
|
}
|
|
12135
12140
|
}
|
|
12141
|
+
async function callGenerateWireUploadUrlFromPlugin(apiKey2, args) {
|
|
12142
|
+
if (authCircuitOpen) {
|
|
12143
|
+
throw new Error(
|
|
12144
|
+
'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_..."'
|
|
12145
|
+
);
|
|
12146
|
+
}
|
|
12147
|
+
const c = getClient();
|
|
12148
|
+
if (!c) {
|
|
12149
|
+
throw new Error("Convex client not initialized \u2014 subscription may not be active");
|
|
12150
|
+
}
|
|
12151
|
+
try {
|
|
12152
|
+
return await c.mutation(generateWireUploadUrlFromPluginRef, {
|
|
12153
|
+
apiKeyHash: hashApiKey(apiKey2),
|
|
12154
|
+
agentName: args.agentName
|
|
12155
|
+
});
|
|
12156
|
+
} catch (err) {
|
|
12157
|
+
if (isUnauthorizedError(err)) {
|
|
12158
|
+
tripAuthCircuit();
|
|
12159
|
+
}
|
|
12160
|
+
throw err;
|
|
12161
|
+
}
|
|
12162
|
+
}
|
|
12163
|
+
async function callPublishWireFromPlugin(apiKey2, args) {
|
|
12164
|
+
if (authCircuitOpen) {
|
|
12165
|
+
throw new Error(
|
|
12166
|
+
'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_..."'
|
|
12167
|
+
);
|
|
12168
|
+
}
|
|
12169
|
+
const c = getClient();
|
|
12170
|
+
if (!c) {
|
|
12171
|
+
throw new Error("Convex client not initialized \u2014 subscription may not be active");
|
|
12172
|
+
}
|
|
12173
|
+
try {
|
|
12174
|
+
return await c.mutation(publishWireFromPluginRef, {
|
|
12175
|
+
apiKeyHash: hashApiKey(apiKey2),
|
|
12176
|
+
agentName: args.agentName,
|
|
12177
|
+
kind: args.kind,
|
|
12178
|
+
title: args.title,
|
|
12179
|
+
brief: args.brief,
|
|
12180
|
+
...args.body !== void 0 ? { body: args.body } : {},
|
|
12181
|
+
...args.storageId !== void 0 ? { storageId: args.storageId } : {},
|
|
12182
|
+
...args.mimeType !== void 0 ? { mimeType: args.mimeType } : {},
|
|
12183
|
+
...args.filename !== void 0 ? { filename: args.filename } : {},
|
|
12184
|
+
...args.altText !== void 0 ? { altText: args.altText } : {},
|
|
12185
|
+
...args.roomId !== void 0 ? { roomId: args.roomId } : {},
|
|
12186
|
+
...args.taskId !== void 0 ? { taskId: args.taskId } : {}
|
|
12187
|
+
});
|
|
12188
|
+
} catch (err) {
|
|
12189
|
+
if (isUnauthorizedError(err)) {
|
|
12190
|
+
tripAuthCircuit();
|
|
12191
|
+
}
|
|
12192
|
+
throw err;
|
|
12193
|
+
}
|
|
12194
|
+
}
|
|
12136
12195
|
async function callStartModerationSessionFromPlugin(apiKey2, args) {
|
|
12137
12196
|
if (authCircuitOpen) {
|
|
12138
12197
|
throw new Error(
|
|
@@ -12295,6 +12354,8 @@ TOOLS: Use these \u2014 do NOT call the REST API directly.
|
|
|
12295
12354
|
- cohort_room_cancel_moderation_session(session_id, reason?) \u2014 moderator only: cancel an in-flight session
|
|
12296
12355
|
- 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
12356
|
- 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)
|
|
12357
|
+
- wire_publish(kind, title, brief, body?, image_base64?, mime_type?, filename?, alt_text?, room_id?, task_id?, in_response_to_steer_id?, delivery_note?) - publish a report or image to Cohort Wire; include in_response_to_steer_id when a WIRE REQUEST block asks for it
|
|
12358
|
+
- wire_decline(steer_id, reason) - decline a Wire request you cannot complete
|
|
12298
12359
|
- cohort_task(task_number) \u2014 fetch full task details + comments
|
|
12299
12360
|
- cohort_transition(task_number, status) \u2014 change status
|
|
12300
12361
|
- cohort_assign(task_number, assignee) \u2014 assign/unassign
|
|
@@ -12357,6 +12418,9 @@ function isHumanQuestionRoutingRequest(n) {
|
|
|
12357
12418
|
}
|
|
12358
12419
|
function roomMessageCta(n) {
|
|
12359
12420
|
const roomId = n.roomId ?? "unknown";
|
|
12421
|
+
if (n.wireSteerContext != null && renderWireSteerContext(n.wireSteerContext) !== "") {
|
|
12422
|
+
return "Follow the WIRE REQUEST block in this message \u2014 it is authoritative.";
|
|
12423
|
+
}
|
|
12360
12424
|
if (n.moderationContext != null && renderModerationContext(n.moderationContext) !== "") {
|
|
12361
12425
|
return "Follow the MODERATION SESSION block in this message \u2014 it is authoritative.";
|
|
12362
12426
|
}
|
|
@@ -12405,6 +12469,47 @@ function renderModerationContext(ctx) {
|
|
|
12405
12469
|
lines.push("[/MODERATION SESSION]");
|
|
12406
12470
|
return lines.join("\n");
|
|
12407
12471
|
}
|
|
12472
|
+
function renderWireSteerContext(ctx) {
|
|
12473
|
+
if (ctx.version !== 1) return "";
|
|
12474
|
+
const artifact = ctx.artifact;
|
|
12475
|
+
const lines = [
|
|
12476
|
+
`[WIRE REQUEST ${ctx.steerId}]`,
|
|
12477
|
+
`Mode: ${ctx.mode} | Contract: ${ctx.contract} | Source: ${artifact.type} ${ctx.wireItemId}`,
|
|
12478
|
+
`Title: ${artifact.title}`,
|
|
12479
|
+
`Brief: ${artifact.brief}`
|
|
12480
|
+
];
|
|
12481
|
+
if (artifact.body) {
|
|
12482
|
+
lines.push("Artifact body:", artifact.body);
|
|
12483
|
+
}
|
|
12484
|
+
if (artifact.imageUrl) {
|
|
12485
|
+
lines.push(`Artifact URL: ${artifact.imageUrl}`);
|
|
12486
|
+
}
|
|
12487
|
+
lines.push(`Instruction: ${ctx.instruction}`);
|
|
12488
|
+
if (ctx.comments.length > 0) {
|
|
12489
|
+
lines.push(
|
|
12490
|
+
"Recent thread:",
|
|
12491
|
+
...ctx.comments.map(
|
|
12492
|
+
(comment) => `- ${comment.authorName} (${comment.authorType}): ${comment.body}`
|
|
12493
|
+
)
|
|
12494
|
+
);
|
|
12495
|
+
} else {
|
|
12496
|
+
lines.push("Recent thread: (none)");
|
|
12497
|
+
}
|
|
12498
|
+
const provenance = [
|
|
12499
|
+
ctx.provenance.roomId ? `roomId=${ctx.provenance.roomId}` : "",
|
|
12500
|
+
ctx.provenance.taskId ? `taskId=${ctx.provenance.taskId}` : "",
|
|
12501
|
+
ctx.provenance.sessionId ? `sessionId=${ctx.provenance.sessionId}` : "",
|
|
12502
|
+
ctx.provenance.revisesItemId ? `revisesItemId=${ctx.provenance.revisesItemId}` : "",
|
|
12503
|
+
ctx.provenance.derivedFromItemId ? `derivedFromItemId=${ctx.provenance.derivedFromItemId}` : ""
|
|
12504
|
+
].filter(Boolean);
|
|
12505
|
+
lines.push(`Provenance: ${provenance.length > 0 ? provenance.join(" | ") : "(none)"}`);
|
|
12506
|
+
lines.push(`NEXT ACTION: ${ctx.deliveryInstruction}`);
|
|
12507
|
+
lines.push(
|
|
12508
|
+
"Do NOT deliver by commenting. Use wire_publish with inResponseToSteerId so Cohort can link the result.",
|
|
12509
|
+
"[/WIRE REQUEST]"
|
|
12510
|
+
);
|
|
12511
|
+
return lines.join("\n");
|
|
12512
|
+
}
|
|
12408
12513
|
function buildNotificationMessage(n) {
|
|
12409
12514
|
let header;
|
|
12410
12515
|
let cta;
|
|
@@ -12462,8 +12567,9 @@ Scope: ${truncated}`;
|
|
|
12462
12567
|
}
|
|
12463
12568
|
let prompt;
|
|
12464
12569
|
if (n.type === "room_message") {
|
|
12465
|
-
const
|
|
12466
|
-
const
|
|
12570
|
+
const wireSteerBlock = n.wireSteerContext != null ? renderWireSteerContext(n.wireSteerContext) : "";
|
|
12571
|
+
const moderationBlock = !wireSteerBlock && n.moderationContext != null ? renderModerationContext(n.moderationContext) : "";
|
|
12572
|
+
const preamble = wireSteerBlock || moderationBlock || n.behavioralPrompt;
|
|
12467
12573
|
prompt = preamble ? `${preamble}
|
|
12468
12574
|
|
|
12469
12575
|
${ROOM_MESSAGE_RESPONSE_PROMPT}` : ROOM_MESSAGE_RESPONSE_PROMPT;
|
|
@@ -14011,7 +14117,7 @@ function dumpEvent(event) {
|
|
|
14011
14117
|
function positiveNumber(value) {
|
|
14012
14118
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
14013
14119
|
}
|
|
14014
|
-
var PLUGIN_VERSION = true ? "0.
|
|
14120
|
+
var PLUGIN_VERSION = true ? "0.33.0" : "unknown";
|
|
14015
14121
|
function resolveGatewayToken(api) {
|
|
14016
14122
|
const token2 = api.config?.gateway?.auth?.token;
|
|
14017
14123
|
return typeof token2 === "string" ? token2 : null;
|
|
@@ -15031,6 +15137,143 @@ var POCKET_GUIDE = `# Cohort Agent Guide (Pocket Version)
|
|
|
15031
15137
|
function textResult(text, details) {
|
|
15032
15138
|
return { content: [{ type: "text", text }], details: details ?? void 0 };
|
|
15033
15139
|
}
|
|
15140
|
+
var WIRE_TITLE_MAX = 200;
|
|
15141
|
+
var WIRE_BRIEF_MAX = 2e3;
|
|
15142
|
+
var WIRE_BODY_MAX = 32e3;
|
|
15143
|
+
var WIRE_FILENAME_MAX = 200;
|
|
15144
|
+
var WIRE_MIME_TYPE_MAX = 100;
|
|
15145
|
+
var WIRE_ALT_TEXT_MAX = 1e3;
|
|
15146
|
+
var WIRE_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
15147
|
+
function wireInvalid(message) {
|
|
15148
|
+
return textResult(`Cannot publish to Wire: ${message}.`);
|
|
15149
|
+
}
|
|
15150
|
+
function requiredWireString(value, field, maxLength) {
|
|
15151
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
15152
|
+
return { ok: false, message: `${field} is required` };
|
|
15153
|
+
}
|
|
15154
|
+
const trimmed = value.trim();
|
|
15155
|
+
if (trimmed.length > maxLength) {
|
|
15156
|
+
return { ok: false, message: `${field} too long (max ${maxLength} characters)` };
|
|
15157
|
+
}
|
|
15158
|
+
return { ok: true, value: trimmed };
|
|
15159
|
+
}
|
|
15160
|
+
function optionalWireString(value, field, maxLength) {
|
|
15161
|
+
if (value === void 0 || value === null) {
|
|
15162
|
+
return { ok: true };
|
|
15163
|
+
}
|
|
15164
|
+
if (typeof value !== "string") {
|
|
15165
|
+
return { ok: false, message: `${field} must be a string` };
|
|
15166
|
+
}
|
|
15167
|
+
const trimmed = value.trim();
|
|
15168
|
+
if (!trimmed) {
|
|
15169
|
+
return { ok: true };
|
|
15170
|
+
}
|
|
15171
|
+
if (trimmed.length > maxLength) {
|
|
15172
|
+
return { ok: false, message: `${field} too long (max ${maxLength} characters)` };
|
|
15173
|
+
}
|
|
15174
|
+
return { ok: true, value: trimmed };
|
|
15175
|
+
}
|
|
15176
|
+
function decodeWireImageBase64(value) {
|
|
15177
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
15178
|
+
return { ok: false, message: "image_base64 is required" };
|
|
15179
|
+
}
|
|
15180
|
+
const dataUrlMatch = /^data:[^;,]+;base64,([\s\S]*)$/i.exec(value.trim());
|
|
15181
|
+
const normalized = (dataUrlMatch ? dataUrlMatch[1] : value).replace(/\s/g, "");
|
|
15182
|
+
if (!normalized) {
|
|
15183
|
+
return { ok: false, message: "image_base64 is required" };
|
|
15184
|
+
}
|
|
15185
|
+
if (normalized.length % 4 === 1 || !/^[A-Za-z0-9+/]*={0,2}$/.test(normalized)) {
|
|
15186
|
+
return { ok: false, message: "image_base64 must be valid base64" };
|
|
15187
|
+
}
|
|
15188
|
+
const bytes = Buffer2.from(normalized, "base64");
|
|
15189
|
+
if (bytes.byteLength === 0) {
|
|
15190
|
+
return { ok: false, message: "image_base64 is required" };
|
|
15191
|
+
}
|
|
15192
|
+
if (bytes.byteLength > WIRE_IMAGE_MAX_BYTES) {
|
|
15193
|
+
return { ok: false, message: `image too large (max ${WIRE_IMAGE_MAX_BYTES} bytes)` };
|
|
15194
|
+
}
|
|
15195
|
+
return { ok: true, bytes };
|
|
15196
|
+
}
|
|
15197
|
+
function getStorageIdFromUploadResponse(body) {
|
|
15198
|
+
try {
|
|
15199
|
+
const parsed = JSON.parse(body);
|
|
15200
|
+
if (typeof parsed !== "object" || parsed === null || !("storageId" in parsed)) {
|
|
15201
|
+
return null;
|
|
15202
|
+
}
|
|
15203
|
+
const storageId = parsed.storageId;
|
|
15204
|
+
return typeof storageId === "string" && storageId.trim() ? storageId.trim() : null;
|
|
15205
|
+
} catch {
|
|
15206
|
+
return null;
|
|
15207
|
+
}
|
|
15208
|
+
}
|
|
15209
|
+
function formatMetric(metric) {
|
|
15210
|
+
return `${metric.current}/${metric.target} ${metric.unit}`;
|
|
15211
|
+
}
|
|
15212
|
+
function redactSecrets(text) {
|
|
15213
|
+
return text.replace(/ch_(?:live|test)_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
15214
|
+
}
|
|
15215
|
+
async function safeHttpError(response) {
|
|
15216
|
+
try {
|
|
15217
|
+
const body = await response.text();
|
|
15218
|
+
const parsed = JSON.parse(body);
|
|
15219
|
+
if (parsed && typeof parsed === "object") {
|
|
15220
|
+
const record = parsed;
|
|
15221
|
+
const message = typeof record.message === "string" ? record.message : record.error && typeof record.error === "object" && typeof record.error.message === "string" ? record.error.message : typeof record.error === "string" ? record.error : null;
|
|
15222
|
+
return message ? `: ${redactSecrets(message).slice(0, 300)}` : "";
|
|
15223
|
+
}
|
|
15224
|
+
} catch {
|
|
15225
|
+
}
|
|
15226
|
+
return "";
|
|
15227
|
+
}
|
|
15228
|
+
function renderTaskContext(context) {
|
|
15229
|
+
if (!context) return "";
|
|
15230
|
+
const lines = [];
|
|
15231
|
+
if (context.initiative) {
|
|
15232
|
+
const suffix = context.initiative.description ? ` \u2014 ${context.initiative.description}` : "";
|
|
15233
|
+
lines.push(`**Initiative:** ${context.initiative.name}${suffix}`);
|
|
15234
|
+
}
|
|
15235
|
+
if (context.goal) {
|
|
15236
|
+
const metric = context.goal.metric ? ` \u2014 ${formatMetric(context.goal.metric)}` : "";
|
|
15237
|
+
lines.push(`**Goal:** ${context.goal.title} (${context.goal.status})${metric}`);
|
|
15238
|
+
if (context.goal.test) {
|
|
15239
|
+
lines.push(`**Test:** ${context.goal.test}`);
|
|
15240
|
+
}
|
|
15241
|
+
}
|
|
15242
|
+
if (context.project) {
|
|
15243
|
+
const projectDetails = [context.project.status];
|
|
15244
|
+
if (context.project.progress) {
|
|
15245
|
+
projectDetails.push(`${context.project.progress.done}/${context.project.progress.total} tasks done`);
|
|
15246
|
+
}
|
|
15247
|
+
if (context.project.targetDate) {
|
|
15248
|
+
projectDetails.push(`target ${context.project.targetDate}`);
|
|
15249
|
+
}
|
|
15250
|
+
lines.push(`**Project:** ${context.project.title} (${projectDetails.join(", ")})`);
|
|
15251
|
+
}
|
|
15252
|
+
return lines.length > 0 ? ["## Why this matters", ...lines].join("\n") : "";
|
|
15253
|
+
}
|
|
15254
|
+
function renderGoal(goal) {
|
|
15255
|
+
const lines = [
|
|
15256
|
+
`# Goal: ${goal.title}`,
|
|
15257
|
+
`**Status:** ${goal.status}`
|
|
15258
|
+
];
|
|
15259
|
+
if (goal.description) {
|
|
15260
|
+
lines.push("", "## Description", goal.description);
|
|
15261
|
+
}
|
|
15262
|
+
if (goal.test) {
|
|
15263
|
+
lines.push("", `**Test:** ${goal.test}`);
|
|
15264
|
+
}
|
|
15265
|
+
if (goal.metric) {
|
|
15266
|
+
lines.push(`**Metric:** ${formatMetric(goal.metric)}`);
|
|
15267
|
+
}
|
|
15268
|
+
if (goal.lastVerification) {
|
|
15269
|
+
const result = goal.lastVerification.passed ? "passed" : "failed";
|
|
15270
|
+
lines.push(
|
|
15271
|
+
`**Last verification:** ${result} by ${goal.lastVerification.byName} (${goal.lastVerification.byType}) at ${goal.lastVerification.at}`,
|
|
15272
|
+
`**Evidence:** ${goal.lastVerification.evidence}`
|
|
15273
|
+
);
|
|
15274
|
+
}
|
|
15275
|
+
return lines.join("\n");
|
|
15276
|
+
}
|
|
15034
15277
|
var sharedHookState = null;
|
|
15035
15278
|
var plugin = definePluginEntry({
|
|
15036
15279
|
id: "cohort-sync",
|
|
@@ -15224,6 +15467,112 @@ Do not attempt more comments until tomorrow.`);
|
|
|
15224
15467
|
}
|
|
15225
15468
|
};
|
|
15226
15469
|
});
|
|
15470
|
+
api.registerTool((toolCtx) => {
|
|
15471
|
+
const agentId = toolCtx.agentId ?? "main";
|
|
15472
|
+
return {
|
|
15473
|
+
name: "wire_publish",
|
|
15474
|
+
label: "wire_publish",
|
|
15475
|
+
description: "Publish a report or image to Cohort Wire. For images, pass base64 bytes plus image metadata; the tool uploads the file before publishing.",
|
|
15476
|
+
parameters: Type.Object({
|
|
15477
|
+
kind: Type.Union([
|
|
15478
|
+
Type.Literal("report"),
|
|
15479
|
+
Type.Literal("image")
|
|
15480
|
+
], { description: 'Publish kind: "report" for text documents, "image" for image files.' }),
|
|
15481
|
+
title: Type.String({ description: `Title shown in Wire, max ${WIRE_TITLE_MAX} characters.` }),
|
|
15482
|
+
brief: Type.String({ description: `Short summary shown in Wire, max ${WIRE_BRIEF_MAX} characters.` }),
|
|
15483
|
+
body: Type.Optional(Type.String({ description: `Report markdown/body text, max ${WIRE_BODY_MAX} characters. Used with kind=report.` })),
|
|
15484
|
+
image_base64: Type.Optional(Type.String({ description: `Base64 image bytes, max ${WIRE_IMAGE_MAX_BYTES} decoded bytes. Used with kind=image.` })),
|
|
15485
|
+
mime_type: Type.Optional(Type.String({ description: `Image MIME type such as image/png, max ${WIRE_MIME_TYPE_MAX} characters. Used with kind=image.` })),
|
|
15486
|
+
filename: Type.Optional(Type.String({ description: `Original image filename, max ${WIRE_FILENAME_MAX} characters. Used with kind=image.` })),
|
|
15487
|
+
alt_text: Type.Optional(Type.String({ description: `Accessible image description, max ${WIRE_ALT_TEXT_MAX} characters. Used with kind=image.` })),
|
|
15488
|
+
room_id: Type.Optional(Type.String({ description: "Optional Cohort Room ID to link this Wire item to." })),
|
|
15489
|
+
task_id: Type.Optional(Type.String({ description: "Optional Cohort task ID to link this Wire item to." }))
|
|
15490
|
+
}),
|
|
15491
|
+
async execute(_toolCallId, params) {
|
|
15492
|
+
const rt = getToolRuntime();
|
|
15493
|
+
if (!rt.isReady) {
|
|
15494
|
+
return textResult("wire_publish is not ready yet - the plugin is still starting up. Try again in a few seconds.");
|
|
15495
|
+
}
|
|
15496
|
+
const title = requiredWireString(params.title, "title", WIRE_TITLE_MAX);
|
|
15497
|
+
if (!title.ok) return wireInvalid(title.message);
|
|
15498
|
+
const brief = requiredWireString(params.brief, "brief", WIRE_BRIEF_MAX);
|
|
15499
|
+
if (!brief.ok) return wireInvalid(brief.message);
|
|
15500
|
+
const roomId = optionalWireString(params.room_id, "room_id", WIRE_TITLE_MAX);
|
|
15501
|
+
if (!roomId.ok) return wireInvalid(roomId.message);
|
|
15502
|
+
const taskId = optionalWireString(params.task_id, "task_id", WIRE_TITLE_MAX);
|
|
15503
|
+
if (!taskId.ok) return wireInvalid(taskId.message);
|
|
15504
|
+
const agentName = rt.resolveAgentName(agentId);
|
|
15505
|
+
if (params.kind === "report") {
|
|
15506
|
+
const body = optionalWireString(params.body, "body", WIRE_BODY_MAX);
|
|
15507
|
+
if (!body.ok) return wireInvalid(body.message);
|
|
15508
|
+
try {
|
|
15509
|
+
const result = await callPublishWireFromPlugin(rt.apiKey, {
|
|
15510
|
+
agentName,
|
|
15511
|
+
kind: "report",
|
|
15512
|
+
title: title.value,
|
|
15513
|
+
brief: brief.value,
|
|
15514
|
+
...body.value !== void 0 ? { body: body.value } : {},
|
|
15515
|
+
...roomId.value !== void 0 ? { roomId: roomId.value } : {},
|
|
15516
|
+
...taskId.value !== void 0 ? { taskId: taskId.value } : {}
|
|
15517
|
+
});
|
|
15518
|
+
return textResult(`Published report to Wire.
|
|
15519
|
+
Wire item: ${result.wireItemId}`, result);
|
|
15520
|
+
} catch (err) {
|
|
15521
|
+
const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
|
|
15522
|
+
return textResult(`Failed to publish to Wire: ${msg}`);
|
|
15523
|
+
}
|
|
15524
|
+
}
|
|
15525
|
+
if (params.kind !== "image") {
|
|
15526
|
+
return wireInvalid('kind must be "report" or "image"');
|
|
15527
|
+
}
|
|
15528
|
+
const mimeType = requiredWireString(params.mime_type, "mime_type", WIRE_MIME_TYPE_MAX);
|
|
15529
|
+
if (!mimeType.ok) return wireInvalid(mimeType.message);
|
|
15530
|
+
if (!mimeType.value.startsWith("image/")) {
|
|
15531
|
+
return wireInvalid("mime_type must start with image/");
|
|
15532
|
+
}
|
|
15533
|
+
const filename = requiredWireString(params.filename, "filename", WIRE_FILENAME_MAX);
|
|
15534
|
+
if (!filename.ok) return wireInvalid(filename.message);
|
|
15535
|
+
const altText = requiredWireString(params.alt_text, "alt_text", WIRE_ALT_TEXT_MAX);
|
|
15536
|
+
if (!altText.ok) return wireInvalid(altText.message);
|
|
15537
|
+
const image = decodeWireImageBase64(params.image_base64);
|
|
15538
|
+
if (!image.ok) return wireInvalid(image.message);
|
|
15539
|
+
try {
|
|
15540
|
+
const uploadUrl = await callGenerateWireUploadUrlFromPlugin(rt.apiKey, { agentName });
|
|
15541
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
15542
|
+
method: "POST",
|
|
15543
|
+
headers: { "Content-Type": mimeType.value },
|
|
15544
|
+
body: new Blob([image.bytes], { type: mimeType.value }),
|
|
15545
|
+
signal: AbortSignal.timeout(3e4)
|
|
15546
|
+
});
|
|
15547
|
+
const uploadBody = await uploadResponse.text();
|
|
15548
|
+
if (!uploadResponse.ok) {
|
|
15549
|
+
return textResult(`Failed to upload image to Wire: ${uploadResponse.status} ${uploadBody.slice(0, 300)}`);
|
|
15550
|
+
}
|
|
15551
|
+
const storageId = getStorageIdFromUploadResponse(uploadBody);
|
|
15552
|
+
if (!storageId) {
|
|
15553
|
+
return textResult("Failed to upload image to Wire: upload response did not include storageId.");
|
|
15554
|
+
}
|
|
15555
|
+
const result = await callPublishWireFromPlugin(rt.apiKey, {
|
|
15556
|
+
agentName,
|
|
15557
|
+
kind: "image",
|
|
15558
|
+
title: title.value,
|
|
15559
|
+
brief: brief.value,
|
|
15560
|
+
storageId,
|
|
15561
|
+
mimeType: mimeType.value,
|
|
15562
|
+
filename: filename.value,
|
|
15563
|
+
altText: altText.value,
|
|
15564
|
+
...roomId.value !== void 0 ? { roomId: roomId.value } : {},
|
|
15565
|
+
...taskId.value !== void 0 ? { taskId: taskId.value } : {}
|
|
15566
|
+
});
|
|
15567
|
+
return textResult(`Published image to Wire.
|
|
15568
|
+
Wire item: ${result.wireItemId}`, result);
|
|
15569
|
+
} catch (err) {
|
|
15570
|
+
const msg = getConvexAppErrorMessage(err) ?? (err instanceof Error ? err.message : String(err));
|
|
15571
|
+
return textResult(`Failed to publish to Wire: ${msg}`);
|
|
15572
|
+
}
|
|
15573
|
+
}
|
|
15574
|
+
};
|
|
15575
|
+
});
|
|
15227
15576
|
api.registerTool((toolCtx) => {
|
|
15228
15577
|
const agentId = toolCtx.agentId ?? "main";
|
|
15229
15578
|
return {
|
|
@@ -15478,11 +15827,13 @@ ${body}`,
|
|
|
15478
15827
|
`# Task #${task.taskNumber}: ${task.title}`,
|
|
15479
15828
|
`**Status:** ${task.status} | **Priority:** ${task.priority ?? "none"} | **Effort:** ${task.effort ?? "none"}`,
|
|
15480
15829
|
`**Assigned to:** ${task.assignedTo ?? "unassigned"}`,
|
|
15481
|
-
`**Created:** ${task.createdAt}
|
|
15482
|
-
"",
|
|
15483
|
-
"## Description",
|
|
15484
|
-
task.description || "(no description)"
|
|
15830
|
+
`**Created:** ${task.createdAt}`
|
|
15485
15831
|
];
|
|
15832
|
+
const contextBlock = renderTaskContext(task.context);
|
|
15833
|
+
if (contextBlock) {
|
|
15834
|
+
lines.push("", contextBlock);
|
|
15835
|
+
}
|
|
15836
|
+
lines.push("", "## Description", task.description || "(no description)");
|
|
15486
15837
|
if (params.include_comments !== false) {
|
|
15487
15838
|
const limit = params.comment_limit ?? 10;
|
|
15488
15839
|
const commentsRes = await fetch(
|
|
@@ -15513,6 +15864,62 @@ ${body}`,
|
|
|
15513
15864
|
}
|
|
15514
15865
|
};
|
|
15515
15866
|
});
|
|
15867
|
+
api.registerTool(() => {
|
|
15868
|
+
return {
|
|
15869
|
+
name: "cohort_goal",
|
|
15870
|
+
label: "cohort_goal",
|
|
15871
|
+
description: "Fetch a Cohort goal \u2014 including its test \u2014 or submit a verification result after running the test. A goal's test tells you how to check whether the outcome is achieved.",
|
|
15872
|
+
parameters: Type.Object({
|
|
15873
|
+
goal_id: Type.String({ description: "Goal ID from Cohort." }),
|
|
15874
|
+
verify: Type.Optional(Type.Object({
|
|
15875
|
+
passed: Type.Boolean({ description: "Whether the goal test passed." }),
|
|
15876
|
+
evidence: Type.String({ description: "Evidence from running the test." }),
|
|
15877
|
+
metric_current: Type.Optional(Type.Number({ description: "Updated current metric value, if the goal has a metric." }))
|
|
15878
|
+
}))
|
|
15879
|
+
}),
|
|
15880
|
+
async execute(_toolCallId, params) {
|
|
15881
|
+
const rt = getToolRuntime();
|
|
15882
|
+
if (!rt.isReady) {
|
|
15883
|
+
return textResult("cohort_goal is not ready yet \u2014 the plugin is still starting up.");
|
|
15884
|
+
}
|
|
15885
|
+
const goalUrl = `${rt.apiUrl}/api/v1/goals/${encodeURIComponent(params.goal_id)}`;
|
|
15886
|
+
try {
|
|
15887
|
+
const response = await fetch(
|
|
15888
|
+
params.verify ? `${goalUrl}/verify` : goalUrl,
|
|
15889
|
+
{
|
|
15890
|
+
method: params.verify ? "POST" : "GET",
|
|
15891
|
+
headers: {
|
|
15892
|
+
"Authorization": `Bearer ${rt.apiKey}`,
|
|
15893
|
+
...params.verify ? { "Content-Type": "application/json" } : {}
|
|
15894
|
+
},
|
|
15895
|
+
...params.verify ? {
|
|
15896
|
+
body: JSON.stringify({
|
|
15897
|
+
passed: params.verify.passed,
|
|
15898
|
+
evidence: params.verify.evidence,
|
|
15899
|
+
...params.verify.metric_current !== void 0 ? { metricCurrent: params.verify.metric_current } : {}
|
|
15900
|
+
})
|
|
15901
|
+
} : {},
|
|
15902
|
+
signal: AbortSignal.timeout(1e4)
|
|
15903
|
+
}
|
|
15904
|
+
);
|
|
15905
|
+
if (!response.ok) {
|
|
15906
|
+
const message = await safeHttpError(response);
|
|
15907
|
+
return textResult(`Failed to fetch goal ${params.goal_id}: ${response.status}${message}`);
|
|
15908
|
+
}
|
|
15909
|
+
const goal = await response.json();
|
|
15910
|
+
if (!params.verify) {
|
|
15911
|
+
return textResult(renderGoal(goal), goal);
|
|
15912
|
+
}
|
|
15913
|
+
const explanation = goal.status === "verification_pending" ? "Reported. A human will confirm before the goal is marked met." : goal.status === "met" ? "Goal marked met." : `Verification recorded. Goal status: ${goal.status}.`;
|
|
15914
|
+
return textResult(`${explanation}
|
|
15915
|
+
|
|
15916
|
+
${renderGoal(goal)}`, goal);
|
|
15917
|
+
} catch (err) {
|
|
15918
|
+
return textResult(`Failed to fetch goal ${params.goal_id}: ${err instanceof Error ? redactSecrets(err.message) : "Unknown error"}`);
|
|
15919
|
+
}
|
|
15920
|
+
}
|
|
15921
|
+
};
|
|
15922
|
+
});
|
|
15516
15923
|
api.registerTool((toolCtx) => {
|
|
15517
15924
|
const agentId = toolCtx.agentId ?? "main";
|
|
15518
15925
|
return {
|
|
@@ -15620,5 +16027,6 @@ ${body}`,
|
|
|
15620
16027
|
});
|
|
15621
16028
|
var index_default = plugin;
|
|
15622
16029
|
export {
|
|
15623
|
-
index_default as default
|
|
16030
|
+
index_default as default,
|
|
16031
|
+
renderTaskContext
|
|
15624
16032
|
};
|
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
"cohort_room_start_moderation_session",
|
|
18
18
|
"cohort_room_advance_moderation_session",
|
|
19
19
|
"cohort_room_cancel_moderation_session",
|
|
20
|
+
"wire_publish",
|
|
20
21
|
"cohort_context",
|
|
21
22
|
"cohort_briefing_context",
|
|
22
23
|
"cohort_briefing",
|
|
23
24
|
"cohort_task",
|
|
25
|
+
"cohort_goal",
|
|
24
26
|
"cohort_transition",
|
|
25
27
|
"cohort_assign"
|
|
26
28
|
]
|
|
@@ -80,5 +82,5 @@
|
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
},
|
|
83
|
-
"version": "0.
|
|
85
|
+
"version": "0.33.0"
|
|
84
86
|
}
|
package/dist/package.json
CHANGED
package/openclaw.plugin.json
CHANGED
|
@@ -15,10 +15,12 @@
|
|
|
15
15
|
"cohort_room_start_moderation_session",
|
|
16
16
|
"cohort_room_advance_moderation_session",
|
|
17
17
|
"cohort_room_cancel_moderation_session",
|
|
18
|
+
"wire_publish",
|
|
18
19
|
"cohort_context",
|
|
19
20
|
"cohort_briefing_context",
|
|
20
21
|
"cohort_briefing",
|
|
21
22
|
"cohort_task",
|
|
23
|
+
"cohort_goal",
|
|
22
24
|
"cohort_transition",
|
|
23
25
|
"cohort_assign"
|
|
24
26
|
]
|
package/package.json
CHANGED