@kynver-app/openclaw-agent-os 0.1.31 → 0.1.36
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 +312 -4
- package/dist/index.js.map +3 -3
- package/openclaw.plugin.json +6 -0
- package/package.json +1 -1
- package/scripts/bootstrap-openclaw.mjs +8 -2
package/dist/index.js
CHANGED
|
@@ -63,6 +63,11 @@ var pluginConfigSchema = {
|
|
|
63
63
|
default: true,
|
|
64
64
|
description: "Inject a system-context block telling OpenClaw turns to use AgentOS (get_context, search_memory, write_memory, sessions, projects, goals) as the primary continuity store and to treat local markdown memory as fallback only."
|
|
65
65
|
},
|
|
66
|
+
enableTelegramReplyContext: {
|
|
67
|
+
type: "boolean",
|
|
68
|
+
default: true,
|
|
69
|
+
description: "Preserve Telegram reply-thread context on visible outbound messages via reply_dispatch + message_sending hooks (reply_to tags and Re: subject prefixes)."
|
|
70
|
+
},
|
|
66
71
|
runtimeSkillManifestTtlMs: {
|
|
67
72
|
type: "number",
|
|
68
73
|
default: 6e4,
|
|
@@ -86,6 +91,11 @@ var pluginConfigSchema = {
|
|
|
86
91
|
harnessRepo: {
|
|
87
92
|
type: "string",
|
|
88
93
|
description: "Default git repo path for harness run create/dispatch. Required when enableHarnessTools is true. Falls back to KYNVER_HARNESS_REPO."
|
|
94
|
+
},
|
|
95
|
+
enableTelegramToolErrorFilter: {
|
|
96
|
+
type: "boolean",
|
|
97
|
+
default: true,
|
|
98
|
+
description: "When true, suppress raw failed exec/tool/worktree lines on Telegram and webchat direct chat (OpenClaw message_sending hook)."
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
};
|
|
@@ -106,11 +116,13 @@ function resolvePluginConfig(rawEntry) {
|
|
|
106
116
|
enableSessionLifecycle: typeof raw?.enableSessionLifecycle === "boolean" ? raw.enableSessionLifecycle : true,
|
|
107
117
|
enableRuntimeSkillManifest: typeof raw?.enableRuntimeSkillManifest === "boolean" ? raw.enableRuntimeSkillManifest : true,
|
|
108
118
|
enableContinuityGuidance: typeof raw?.enableContinuityGuidance === "boolean" ? raw.enableContinuityGuidance : true,
|
|
119
|
+
enableTelegramReplyContext: typeof raw?.enableTelegramReplyContext === "boolean" ? raw.enableTelegramReplyContext : true,
|
|
109
120
|
runtimeSkillManifestTtlMs: typeof raw?.runtimeSkillManifestTtlMs === "number" && Number.isFinite(raw.runtimeSkillManifestTtlMs) && raw.runtimeSkillManifestTtlMs > 0 ? raw.runtimeSkillManifestTtlMs : 6e4,
|
|
110
121
|
runtimeSkillManifestTimeoutMs: typeof raw?.runtimeSkillManifestTimeoutMs === "number" && Number.isFinite(raw.runtimeSkillManifestTimeoutMs) && raw.runtimeSkillManifestTimeoutMs > 0 ? raw.runtimeSkillManifestTimeoutMs : 1e4,
|
|
111
122
|
runtimeSkillManifestMaxSkills: typeof raw?.runtimeSkillManifestMaxSkills === "number" && Number.isFinite(raw.runtimeSkillManifestMaxSkills) && raw.runtimeSkillManifestMaxSkills > 0 ? Math.floor(raw.runtimeSkillManifestMaxSkills) : 25,
|
|
112
123
|
enableHarnessTools: typeof raw?.enableHarnessTools === "boolean" ? raw.enableHarnessTools : false,
|
|
113
|
-
harnessRepo: typeof raw?.harnessRepo === "string" && raw.harnessRepo.trim() ? raw.harnessRepo.trim() : process.env.KYNVER_HARNESS_REPO?.trim() || void 0
|
|
124
|
+
harnessRepo: typeof raw?.harnessRepo === "string" && raw.harnessRepo.trim() ? raw.harnessRepo.trim() : process.env.KYNVER_HARNESS_REPO?.trim() || void 0,
|
|
125
|
+
enableTelegramToolErrorFilter: typeof raw?.enableTelegramToolErrorFilter === "boolean" ? raw.enableTelegramToolErrorFilter : true
|
|
114
126
|
};
|
|
115
127
|
}
|
|
116
128
|
|
|
@@ -729,6 +741,14 @@ function directRequestForTool(toolName2, params, resolvedSlug) {
|
|
|
729
741
|
method: "GET",
|
|
730
742
|
path: `/command-center${queryString(params, ["since", "limit", "harnessLimit"])}`
|
|
731
743
|
};
|
|
744
|
+
case "agent_os_command_center_dashboard_contract_get":
|
|
745
|
+
return {
|
|
746
|
+
route: "by-id",
|
|
747
|
+
agentOsId: stringParam(params.agentOsId),
|
|
748
|
+
slug,
|
|
749
|
+
method: "GET",
|
|
750
|
+
path: `/command-center/dashboard-contract${queryString(params, ["since", "limit"])}`
|
|
751
|
+
};
|
|
732
752
|
case "agent_os_task_next_action": {
|
|
733
753
|
const taskId = requiredString(params.taskId, "taskId");
|
|
734
754
|
return {
|
|
@@ -933,8 +953,20 @@ function buildAgentOsContinuityGuidanceContext(config) {
|
|
|
933
953
|
"Local markdown memory (CLAUDE.md, AGENTS.md, /memory, scratch notes) is a fallback and a cache. Use it when AgentOS is unreachable or for in-conversation scratch; do not treat it as authoritative when AgentOS is available.",
|
|
934
954
|
"Tool surface: this OpenClaw plugin registers only AgentOS tools (agent_os_*). The Kynver in-app chat agent separately scopes MCP domain tools via MARM hybrid search over McpTool \u2014 it does not inject the full ~200+ tool catalog each turn. Do not paste full MCP JSON schemas into local files; call the tools you need.",
|
|
935
955
|
"Privacy: AgentOS context is personal to the signed-in account. Do not expose AgentOS identity, goals, projects, contacts, or memory excerpts in shared, broadcast, group, or multi-tenant contexts unless the user explicitly asks for it. If you cannot determine the channel scope, withhold AgentOS specifics by default.",
|
|
956
|
+
"",
|
|
957
|
+
"Telegram reply-thread UX:",
|
|
958
|
+
"- When Conversation info (untrusted metadata) includes reply_to_id or has_reply_context, or the turn includes a Reply target / Current message [Replying to: \u2026] block, treat that quoted/status text as the subject of the user's question.",
|
|
959
|
+
'- Visible replies must make the target obvious: either send as a threaded reply (message tool / native delivery with reply_to) or open the answer by naming what you are addressing (e.g. Re: "<short quote from the reply target>").',
|
|
960
|
+
"- Do not answer a reply-thread/status question with a generic paragraph that ignores the quoted message \u2014 that reads like a memory failure to the operator.",
|
|
936
961
|
"If an AgentOS call fails or returns unavailable, say so explicitly, fall back to local markdown or conversation memory for that turn, and ask the user before persisting anything that would normally go to AgentOS.",
|
|
937
962
|
"",
|
|
963
|
+
"AgentTask priority (capacity queue signal \u2014 not importance):",
|
|
964
|
+
"- Default agent_os_task_create to priority normal (low for routine cleanup). Omit priority to use normal.",
|
|
965
|
+
"- Do NOT copy plan/goal priority onto tasks. Important work stays normal when worker slots are free \u2014 dispatch instead.",
|
|
966
|
+
"- high = harness workers saturated AND ready work waiting for slots (contention only).",
|
|
967
|
+
"- critical = live production/security incident or workstream stop \u2014 cite in priorityEscalationReason or title/description.",
|
|
968
|
+
"- The API downgrades importance-style high/critical; Command Center high-priority counts use effective (capacity-aware) priority.",
|
|
969
|
+
"",
|
|
938
970
|
"Command Center (operational control plane):",
|
|
939
971
|
"- For the same unified rollup the browser Command Center uses (projects, plans, action-required, DQ inbox, harness summaries, runtime capacity, packageVersionHealth for @kynver-app/runtime), call agent_os_command_center_get. Omit slug to resolve the account primary workspace; pass agentOsId when you already have it from a prior identity fetch. When packageVersionHealth shows use_repo_source, run from the monorepo checkout (sourceVersionEvidence.consumeCommands) \u2014 never npm publish and never block on operator publish. install_needed/reload_needed may use global installs only when an operator directs it.",
|
|
940
972
|
"",
|
|
@@ -1131,6 +1163,243 @@ function sanitizeRuntimeSkillError(error) {
|
|
|
1131
1163
|
return raw.replace(/(Bearer\s+)[A-Za-z0-9._~+\/-]+/gi, "$1[redacted]").slice(0, 240);
|
|
1132
1164
|
}
|
|
1133
1165
|
|
|
1166
|
+
// src/telegram-reply-context.ts
|
|
1167
|
+
var REPLY_TAG_RE = /\[\[reply_to(?:_current)?(?::[^\]]+)?\]\]/i;
|
|
1168
|
+
function parseTelegramMessageId(value) {
|
|
1169
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
1170
|
+
return Math.trunc(value);
|
|
1171
|
+
}
|
|
1172
|
+
if (typeof value === "string") {
|
|
1173
|
+
const trimmed = value.trim();
|
|
1174
|
+
if (!trimmed) return void 0;
|
|
1175
|
+
const parsed = Number.parseInt(trimmed, 10);
|
|
1176
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
1177
|
+
}
|
|
1178
|
+
return void 0;
|
|
1179
|
+
}
|
|
1180
|
+
function hasInboundReplyMetadata(meta) {
|
|
1181
|
+
if (!meta) return false;
|
|
1182
|
+
if (meta.has_reply_context === true) return true;
|
|
1183
|
+
if (parseTelegramMessageId(meta.reply_to_id) !== void 0) return true;
|
|
1184
|
+
if (typeof meta.reply_to_body === "string" && meta.reply_to_body.trim().length > 0) return true;
|
|
1185
|
+
return false;
|
|
1186
|
+
}
|
|
1187
|
+
function summarizeReplySubject(quote, maxLen = 120) {
|
|
1188
|
+
const collapsed = quote.replace(/\s+/g, " ").trim();
|
|
1189
|
+
if (!collapsed) return "";
|
|
1190
|
+
if (collapsed.length <= maxLen) return collapsed;
|
|
1191
|
+
return `${collapsed.slice(0, Math.max(0, maxLen - 1)).trimEnd()}\u2026`;
|
|
1192
|
+
}
|
|
1193
|
+
function formatReplySubjectPrefix(quote) {
|
|
1194
|
+
const subject = summarizeReplySubject(quote);
|
|
1195
|
+
if (!subject) return "";
|
|
1196
|
+
return `Re: "${subject}"
|
|
1197
|
+
|
|
1198
|
+
`;
|
|
1199
|
+
}
|
|
1200
|
+
function visibleTextReferencesReplyTarget(text, quote) {
|
|
1201
|
+
if (!quote.trim() || !text.trim()) return false;
|
|
1202
|
+
if (REPLY_TAG_RE.test(text)) return true;
|
|
1203
|
+
const subject = summarizeReplySubject(quote, 80).toLowerCase();
|
|
1204
|
+
if (!subject) return false;
|
|
1205
|
+
return text.toLowerCase().includes(subject);
|
|
1206
|
+
}
|
|
1207
|
+
function applyInboundReplyContextToVisibleReply(input) {
|
|
1208
|
+
const baseText = input.text ?? "";
|
|
1209
|
+
const explicitReply = parseTelegramMessageId(input.replyToMessageId);
|
|
1210
|
+
if (explicitReply !== void 0) {
|
|
1211
|
+
return { text: baseText, replyToMessageId: explicitReply };
|
|
1212
|
+
}
|
|
1213
|
+
const inbound = input.inbound;
|
|
1214
|
+
if (!hasInboundReplyMetadata(inbound)) {
|
|
1215
|
+
return { text: baseText };
|
|
1216
|
+
}
|
|
1217
|
+
const threadTarget = parseTelegramMessageId(inbound?.message_id) ?? parseTelegramMessageId(inbound?.reply_to_id);
|
|
1218
|
+
const quote = typeof inbound?.reply_to_body === "string" && inbound.reply_to_body.trim() ? inbound.reply_to_body : "";
|
|
1219
|
+
if (threadTarget !== void 0 && !REPLY_TAG_RE.test(baseText)) {
|
|
1220
|
+
const tag = `[[reply_to:${threadTarget}]]`;
|
|
1221
|
+
const withTag = baseText.startsWith(tag) ? baseText : `${tag}${baseText}`;
|
|
1222
|
+
return { text: withTag, replyToMessageId: threadTarget };
|
|
1223
|
+
}
|
|
1224
|
+
if (quote && !visibleTextReferencesReplyTarget(baseText, quote)) {
|
|
1225
|
+
return { text: `${formatReplySubjectPrefix(quote)}${baseText}` };
|
|
1226
|
+
}
|
|
1227
|
+
return { text: baseText };
|
|
1228
|
+
}
|
|
1229
|
+
function normalizeOptionalString(value) {
|
|
1230
|
+
if (typeof value !== "string") return void 0;
|
|
1231
|
+
const trimmed = value.trim();
|
|
1232
|
+
return trimmed || void 0;
|
|
1233
|
+
}
|
|
1234
|
+
function extractInboundReplyContextFromOpenClawCtx(ctx) {
|
|
1235
|
+
const replyToBody = normalizeOptionalString(ctx.ReplyToBody) ?? normalizeOptionalString(ctx.ReplyToQuoteText);
|
|
1236
|
+
const replyToId = normalizeOptionalString(ctx.ReplyToId);
|
|
1237
|
+
const messageId = normalizeOptionalString(ctx.MessageSid) ?? normalizeOptionalString(ctx.MessageSidFull);
|
|
1238
|
+
const replyChain = ctx.ReplyChain;
|
|
1239
|
+
const hasChain = Array.isArray(replyChain) && replyChain.length > 0;
|
|
1240
|
+
const inbound = {
|
|
1241
|
+
reply_to_id: replyToId,
|
|
1242
|
+
reply_to_body: replyToBody,
|
|
1243
|
+
message_id: messageId,
|
|
1244
|
+
has_reply_context: Boolean(replyToBody || replyToId || hasChain) ? true : void 0
|
|
1245
|
+
};
|
|
1246
|
+
return hasInboundReplyMetadata(inbound) ? inbound : null;
|
|
1247
|
+
}
|
|
1248
|
+
function conversationKeyForOpenClawInbound(ctx) {
|
|
1249
|
+
const channel = normalizeOptionalString(ctx.OriginatingChannel) ?? normalizeOptionalString(ctx.Surface) ?? normalizeOptionalString(ctx.Provider);
|
|
1250
|
+
const chatId = normalizeOptionalString(ctx.OriginatingTo);
|
|
1251
|
+
if (!channel || !chatId) return void 0;
|
|
1252
|
+
return `${channel.toLowerCase()}:${chatId}`;
|
|
1253
|
+
}
|
|
1254
|
+
function isTelegramOpenClawInbound(ctx) {
|
|
1255
|
+
return [ctx.OriginatingChannel, ctx.Surface, ctx.Provider].some(
|
|
1256
|
+
(value) => normalizeOptionalString(value)?.toLowerCase() === "telegram"
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// src/telegram-reply-hooks.ts
|
|
1261
|
+
var STASH_TTL_MS = 15 * 6e4;
|
|
1262
|
+
function pruneStash(stash) {
|
|
1263
|
+
const cutoff = Date.now() - STASH_TTL_MS;
|
|
1264
|
+
for (const [key, entry] of stash) {
|
|
1265
|
+
if (entry.stashedAt < cutoff) stash.delete(key);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
function stashKeyFromSession(sessionKey, conversationKey) {
|
|
1269
|
+
if (sessionKey?.trim()) return `session:${sessionKey.trim()}`;
|
|
1270
|
+
if (conversationKey) return `conv:${conversationKey}`;
|
|
1271
|
+
return void 0;
|
|
1272
|
+
}
|
|
1273
|
+
function registerTelegramReplyContextHooks({
|
|
1274
|
+
api,
|
|
1275
|
+
config
|
|
1276
|
+
}) {
|
|
1277
|
+
if (!config.enableTelegramReplyContext || typeof api?.on !== "function") {
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
const stash = /* @__PURE__ */ new Map();
|
|
1281
|
+
api.on(
|
|
1282
|
+
"reply_dispatch",
|
|
1283
|
+
async (event) => {
|
|
1284
|
+
const record = event;
|
|
1285
|
+
const ctx = record.ctx;
|
|
1286
|
+
if (!ctx || !isTelegramOpenClawInbound(ctx)) return;
|
|
1287
|
+
const inbound = extractInboundReplyContextFromOpenClawCtx(ctx);
|
|
1288
|
+
if (!inbound) return;
|
|
1289
|
+
const conversationKey = conversationKeyForOpenClawInbound(ctx);
|
|
1290
|
+
const key = stashKeyFromSession(record.sessionKey, conversationKey);
|
|
1291
|
+
if (!key) return;
|
|
1292
|
+
pruneStash(stash);
|
|
1293
|
+
stash.set(key, {
|
|
1294
|
+
conversationKey: conversationKey ?? key,
|
|
1295
|
+
inbound,
|
|
1296
|
+
stashedAt: Date.now()
|
|
1297
|
+
});
|
|
1298
|
+
},
|
|
1299
|
+
{ priority: 6, timeoutMs: 500 }
|
|
1300
|
+
);
|
|
1301
|
+
api.on(
|
|
1302
|
+
"message_sending",
|
|
1303
|
+
async (event, channelCtx) => {
|
|
1304
|
+
const sending = event;
|
|
1305
|
+
const ctx = channelCtx;
|
|
1306
|
+
if (ctx.channelId !== "telegram") return;
|
|
1307
|
+
const text = typeof sending.content === "string" ? sending.content : "";
|
|
1308
|
+
if (!text.trim()) return;
|
|
1309
|
+
pruneStash(stash);
|
|
1310
|
+
const convKey = ctx.conversationId ? `telegram:${ctx.conversationId}` : void 0;
|
|
1311
|
+
const stashed = (ctx.sessionKey ? stash.get(`session:${ctx.sessionKey}`) : void 0) ?? (convKey ? stash.get(`conv:${convKey}`) : void 0);
|
|
1312
|
+
if (!stashed) return;
|
|
1313
|
+
const explicitReply = parseTelegramMessageId(sending.replyToId);
|
|
1314
|
+
const adjusted = applyInboundReplyContextToVisibleReply({
|
|
1315
|
+
text,
|
|
1316
|
+
inbound: stashed.inbound,
|
|
1317
|
+
replyToMessageId: explicitReply
|
|
1318
|
+
});
|
|
1319
|
+
if (adjusted.text === text) return { content: text };
|
|
1320
|
+
return { content: adjusted.text };
|
|
1321
|
+
},
|
|
1322
|
+
{ priority: 6, timeoutMs: 2e3 }
|
|
1323
|
+
);
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// src/telegram-tool-error-filter.ts
|
|
1328
|
+
var DIRECT_CHAT_CHANNEL_IDS = /* @__PURE__ */ new Set(["telegram", "webchat"]);
|
|
1329
|
+
var RAW_TOOL_ERROR_WARNING_RE = /^⚠️\s*🛠️\s*.+\bfailed\b/ui;
|
|
1330
|
+
var INTERNAL_TRACE_LINE_RE = /^(?:>\s*)?(?:📊|🛠️|📖|📝|🔍|🔎|⚙️)\s*(?:Session Status|Exec|Read|Edit|Write|Patch|Search|Open|Click|Find|Screenshot|Update Plan|Tool Call|Tool Result|Function Call|Shell|Command)\s*:/i;
|
|
1331
|
+
var COMPACT_TOOL_COMMAND_LINE_RE = /^(?:>\s*)?🛠️\s*(?:(?:(?:elevated|pty)\b\s*(?:·|,)\s*)+)?(?:`{1,2}\s*\S|(?:run|check|fetch|pull|push|view|show|list|switch|create|merge|rebase|stage|restore|reset|stash|search|find|print|copy|move|remove|install|start|cd|git|worktree|pnpm|npm|yarn|bun|node|python|python3|bash|sh)\b)/i;
|
|
1332
|
+
var TOOL_AGENT_SCOPE_RE = /\(in\s+[~\/]|\(agent\)/i;
|
|
1333
|
+
function isDirectChatChannel(channelId) {
|
|
1334
|
+
if (!channelId) return false;
|
|
1335
|
+
const normalized = channelId.trim().toLowerCase();
|
|
1336
|
+
return DIRECT_CHAT_CHANNEL_IDS.has(normalized);
|
|
1337
|
+
}
|
|
1338
|
+
function isRawInternalToolFailureLine(line) {
|
|
1339
|
+
const trimmed = line.trim();
|
|
1340
|
+
if (!trimmed) return false;
|
|
1341
|
+
if (RAW_TOOL_ERROR_WARNING_RE.test(trimmed)) return true;
|
|
1342
|
+
if (INTERNAL_TRACE_LINE_RE.test(trimmed)) return true;
|
|
1343
|
+
if (COMPACT_TOOL_COMMAND_LINE_RE.test(trimmed)) {
|
|
1344
|
+
if (/\bfailed\b/i.test(trimmed)) return true;
|
|
1345
|
+
if (TOOL_AGENT_SCOPE_RE.test(trimmed)) return true;
|
|
1346
|
+
}
|
|
1347
|
+
if (/^🛠️\s+/u.test(trimmed) && /\bfailed\b/i.test(trimmed) && TOOL_AGENT_SCOPE_RE.test(trimmed)) {
|
|
1348
|
+
return true;
|
|
1349
|
+
}
|
|
1350
|
+
return false;
|
|
1351
|
+
}
|
|
1352
|
+
function filterDirectChatOutboundContent(content) {
|
|
1353
|
+
if (!content.trim()) return { action: "pass", content };
|
|
1354
|
+
const lines = content.split(/\r?\n/);
|
|
1355
|
+
const kept = [];
|
|
1356
|
+
let suppressedAny = false;
|
|
1357
|
+
for (const line of lines) {
|
|
1358
|
+
if (isRawInternalToolFailureLine(line)) {
|
|
1359
|
+
suppressedAny = true;
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
kept.push(line);
|
|
1363
|
+
}
|
|
1364
|
+
const next = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
1365
|
+
if (!next) {
|
|
1366
|
+
return suppressedAny ? { action: "suppress", reason: "kynver_suppressed_raw_internal_tool_failure" } : { action: "pass", content: "" };
|
|
1367
|
+
}
|
|
1368
|
+
if (suppressedAny && next !== content.trim()) {
|
|
1369
|
+
return { action: "pass", content: next };
|
|
1370
|
+
}
|
|
1371
|
+
return { action: "pass", content };
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// src/telegram-tool-error-hook.ts
|
|
1375
|
+
function registerTelegramToolErrorFilterHook({
|
|
1376
|
+
api,
|
|
1377
|
+
config
|
|
1378
|
+
}) {
|
|
1379
|
+
if (config.enableTelegramToolErrorFilter === false) return false;
|
|
1380
|
+
if (typeof api?.on !== "function") return false;
|
|
1381
|
+
api.on(
|
|
1382
|
+
"message_sending",
|
|
1383
|
+
async (event, ctx) => {
|
|
1384
|
+
if (!isDirectChatChannel(ctx?.channelId)) return;
|
|
1385
|
+
const content = typeof event?.content === "string" ? event.content : "";
|
|
1386
|
+
if (!content.trim()) return;
|
|
1387
|
+
const filtered = filterDirectChatOutboundContent(content);
|
|
1388
|
+
if (filtered.action === "suppress") {
|
|
1389
|
+
return {
|
|
1390
|
+
cancel: true,
|
|
1391
|
+
cancelReason: filtered.reason
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
if (filtered.content !== content) {
|
|
1395
|
+
return { content: filtered.content };
|
|
1396
|
+
}
|
|
1397
|
+
},
|
|
1398
|
+
{ priority: 8, timeoutMs: 500 }
|
|
1399
|
+
);
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1134
1403
|
// src/schemas/common.ts
|
|
1135
1404
|
var stringArray = {
|
|
1136
1405
|
type: "array",
|
|
@@ -2326,7 +2595,15 @@ var taskExecutorValues = ["inline", "harness", "acp", "manual"];
|
|
|
2326
2595
|
var taskEventTypeValues = ["created", "started", "worker_update", "blocked", "steer", "artifact", "review", "done", "failed"];
|
|
2327
2596
|
var artifactVisibilityValues = ["internal", "telegram_safe", "public_pr_safe"];
|
|
2328
2597
|
var taskStatus = { type: "string", enum: taskStatusValues };
|
|
2329
|
-
var taskPriority = {
|
|
2598
|
+
var taskPriority = {
|
|
2599
|
+
type: "string",
|
|
2600
|
+
enum: taskPriorityValues,
|
|
2601
|
+
description: "Default normal. Priority is a capacity queue signal: high only when workers saturated and ready work waits; critical only for live prod/security incidents (cite in priorityEscalationReason or title/description)."
|
|
2602
|
+
};
|
|
2603
|
+
var priorityEscalationReason = {
|
|
2604
|
+
type: "string",
|
|
2605
|
+
description: "Required for critical: quote Will or name the live incident. Not used for high (contention-only)."
|
|
2606
|
+
};
|
|
2330
2607
|
var taskExecutor = { type: "string", enum: taskExecutorValues };
|
|
2331
2608
|
var taskEventType = { type: "string", enum: taskEventTypeValues };
|
|
2332
2609
|
var artifactVisibility = { type: "string", enum: artifactVisibilityValues };
|
|
@@ -2344,9 +2621,13 @@ var dependsOnTaskIds = {
|
|
|
2344
2621
|
var createTaskSchema = {
|
|
2345
2622
|
type: "object",
|
|
2346
2623
|
properties: {
|
|
2347
|
-
title: {
|
|
2624
|
+
title: {
|
|
2625
|
+
type: "string",
|
|
2626
|
+
description: "Short task title. Do not create closeout-only bookkeeping tasks (board drain, stale-row cleanup, close/cancel-only sweeps) \u2014 update/close the existing AgentTask instead."
|
|
2627
|
+
},
|
|
2348
2628
|
description: { type: "string" },
|
|
2349
2629
|
priority: taskPriority,
|
|
2630
|
+
priorityEscalationReason,
|
|
2350
2631
|
executor: taskExecutor,
|
|
2351
2632
|
executorRef: { type: "string" },
|
|
2352
2633
|
parentTaskId: { type: "string" },
|
|
@@ -2667,6 +2948,26 @@ var slugField = {
|
|
|
2667
2948
|
type: "string",
|
|
2668
2949
|
description: "AgentOS workspace slug. Omit to use the account's primary AgentOS workspace."
|
|
2669
2950
|
};
|
|
2951
|
+
var commandCenterDashboardContractSchema = {
|
|
2952
|
+
type: "object",
|
|
2953
|
+
properties: {
|
|
2954
|
+
slug: slugField,
|
|
2955
|
+
agentOsId: {
|
|
2956
|
+
type: "string",
|
|
2957
|
+
description: "Optional AgentOS row id. When omitted, resolved from slug."
|
|
2958
|
+
},
|
|
2959
|
+
since: {
|
|
2960
|
+
type: "string",
|
|
2961
|
+
description: "ISO timestamp \u2014 only include tasks updated after this instant."
|
|
2962
|
+
},
|
|
2963
|
+
limit: {
|
|
2964
|
+
type: "number",
|
|
2965
|
+
description: "Max tasks to load when building counts (server cap 10000)."
|
|
2966
|
+
}
|
|
2967
|
+
},
|
|
2968
|
+
additionalProperties: false,
|
|
2969
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
2970
|
+
};
|
|
2670
2971
|
var commandCenterGetSchema = {
|
|
2671
2972
|
type: "object",
|
|
2672
2973
|
properties: {
|
|
@@ -2816,9 +3117,14 @@ function createCommandCenterTools(config) {
|
|
|
2816
3117
|
return [
|
|
2817
3118
|
mk(
|
|
2818
3119
|
"agent_os_command_center_get",
|
|
2819
|
-
"Fetch the unified Command Center rollup
|
|
3120
|
+
"Fetch the unified Command Center rollup (includes countSnapshot \u2014 canonical badge counts). Same aggregate as the browser Command Center.",
|
|
2820
3121
|
commandCenterGetSchema
|
|
2821
3122
|
),
|
|
3123
|
+
mk(
|
|
3124
|
+
"agent_os_command_center_dashboard_contract_get",
|
|
3125
|
+
"Slim dashboard contract for runtime verification: countSnapshot, packageVersionHealth, runtime capacity, activePlanRollups \u2014 no graph/hierarchy.",
|
|
3126
|
+
commandCenterDashboardContractSchema
|
|
3127
|
+
),
|
|
2822
3128
|
mk(
|
|
2823
3129
|
"agent_os_task_next_action",
|
|
2824
3130
|
"Route the deterministic next harness action after a worker, reviewer, or landing lane completes (dispatch review/fix/landing, close, or await human). Same POST surface as the production harness completion hook.",
|
|
@@ -2873,7 +3179,9 @@ var plugin = {
|
|
|
2873
3179
|
api.registerTool(tool);
|
|
2874
3180
|
}
|
|
2875
3181
|
registerAgentOsContinuityGuidanceHook({ api, config });
|
|
3182
|
+
registerTelegramReplyContextHooks({ api, config });
|
|
2876
3183
|
registerRuntimeSkillManifestHook({ api, config });
|
|
3184
|
+
registerTelegramToolErrorFilterHook({ api, config });
|
|
2877
3185
|
if (config.enableSessionLifecycle && typeof api.on === "function") {
|
|
2878
3186
|
const sessionIds = /* @__PURE__ */ new Map();
|
|
2879
3187
|
const keyFor = (event, ctx) => String(event?.sessionKey || ctx?.sessionKey || event?.sessionId || ctx?.sessionId || "");
|