@kynver-app/openclaw-agent-os 0.1.30 → 0.1.35
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 +309 -3
- 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 (board create \u2014 checklist):",
|
|
964
|
+
"- Default agent_os_task_create to priority normal (low for routine cleanup). Omit priority to use normal.",
|
|
965
|
+
"- Do NOT copy a plan's or goal's priority onto a new task \u2014 a critical plan still gets normal-priority implementation tasks.",
|
|
966
|
+
"- Use high/critical only when Will explicitly said so in this turn (quote him in priorityEscalationReason) or there is a live production/security incident.",
|
|
967
|
+
"- When worker capacity is available, important work stays normal \u2014 escalate priority only for capacity constraints or explicit user emergency language.",
|
|
968
|
+
"- The API downgrades unsolicited high/critical to normal; blocked tasks are already treated as critical by dispatch/graph logic.",
|
|
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
|
"",
|
|
@@ -954,6 +986,7 @@ function buildAgentOsContinuityGuidanceContext(config) {
|
|
|
954
986
|
"PR landing contract:",
|
|
955
987
|
"- Landing tasks are merge-only. Do not edit files, rebase, resolve conflicts, change package versions, or perform implementation work from a landing lane.",
|
|
956
988
|
"- For chat-visible PR check polling, prefer `node scripts/agent-os-pr-checks-soft.mjs <pr-number-or-url> --repo <owner/repo>` over raw `gh pr checks`. Raw `gh pr checks` exits nonzero for pending checks and creates false failed-tool alerts in Telegram; the soft wrapper exits nonzero only for real failed checks unless `--fail-on-pending` is explicitly requested.",
|
|
989
|
+
"- For repo text search, do not pass a single filename (e.g. `package.json`) as ripgrep's path argument \u2014 that is a file, not a directory. Search from the repo root with a glob (`rg -g package.json <pattern> .`) or use `node scripts/agent-os-repo-search.mjs normalize -- '<command>'` before exec. Searching only `package.json` for `agent-os-land-pr` should use `node scripts/agent-os-land-pr.mjs <pr-url>` directly.",
|
|
957
990
|
"- Land PRs only through the repo's narrow landing wrapper: `node scripts/agent-os-land-pr.mjs <pr-number-or-url>`. The wrapper performs live GitHub readiness checks, squash-merges exactly that PR, deletes the branch, and verifies merged state.",
|
|
958
991
|
"- If the wrapper rejects a PR as draft, conflicted, non-green, pending checks, or missing an exact PR target, mark the landing task blocked with the exact reason instead of improvising a merge path."
|
|
959
992
|
];
|
|
@@ -1130,6 +1163,243 @@ function sanitizeRuntimeSkillError(error) {
|
|
|
1130
1163
|
return raw.replace(/(Bearer\s+)[A-Za-z0-9._~+\/-]+/gi, "$1[redacted]").slice(0, 240);
|
|
1131
1164
|
}
|
|
1132
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
|
+
|
|
1133
1403
|
// src/schemas/common.ts
|
|
1134
1404
|
var stringArray = {
|
|
1135
1405
|
type: "array",
|
|
@@ -2325,7 +2595,15 @@ var taskExecutorValues = ["inline", "harness", "acp", "manual"];
|
|
|
2325
2595
|
var taskEventTypeValues = ["created", "started", "worker_update", "blocked", "steer", "artifact", "review", "done", "failed"];
|
|
2326
2596
|
var artifactVisibilityValues = ["internal", "telegram_safe", "public_pr_safe"];
|
|
2327
2597
|
var taskStatus = { type: "string", enum: taskStatusValues };
|
|
2328
|
-
var taskPriority = {
|
|
2598
|
+
var taskPriority = {
|
|
2599
|
+
type: "string",
|
|
2600
|
+
enum: taskPriorityValues,
|
|
2601
|
+
description: "Default normal. Do not inherit plan/goal priority. high/critical only with priorityEscalationReason (Will quoted or live prod/security incident) \u2014 else server downgrades to normal."
|
|
2602
|
+
};
|
|
2603
|
+
var priorityEscalationReason = {
|
|
2604
|
+
type: "string",
|
|
2605
|
+
description: "When priority is high/critical: cite Will's words or the incident. Required for escalation unless title/description already do."
|
|
2606
|
+
};
|
|
2329
2607
|
var taskExecutor = { type: "string", enum: taskExecutorValues };
|
|
2330
2608
|
var taskEventType = { type: "string", enum: taskEventTypeValues };
|
|
2331
2609
|
var artifactVisibility = { type: "string", enum: artifactVisibilityValues };
|
|
@@ -2346,6 +2624,7 @@ var createTaskSchema = {
|
|
|
2346
2624
|
title: { type: "string", description: "Short task title." },
|
|
2347
2625
|
description: { type: "string" },
|
|
2348
2626
|
priority: taskPriority,
|
|
2627
|
+
priorityEscalationReason,
|
|
2349
2628
|
executor: taskExecutor,
|
|
2350
2629
|
executorRef: { type: "string" },
|
|
2351
2630
|
parentTaskId: { type: "string" },
|
|
@@ -2666,6 +2945,26 @@ var slugField = {
|
|
|
2666
2945
|
type: "string",
|
|
2667
2946
|
description: "AgentOS workspace slug. Omit to use the account's primary AgentOS workspace."
|
|
2668
2947
|
};
|
|
2948
|
+
var commandCenterDashboardContractSchema = {
|
|
2949
|
+
type: "object",
|
|
2950
|
+
properties: {
|
|
2951
|
+
slug: slugField,
|
|
2952
|
+
agentOsId: {
|
|
2953
|
+
type: "string",
|
|
2954
|
+
description: "Optional AgentOS row id. When omitted, resolved from slug."
|
|
2955
|
+
},
|
|
2956
|
+
since: {
|
|
2957
|
+
type: "string",
|
|
2958
|
+
description: "ISO timestamp \u2014 only include tasks updated after this instant."
|
|
2959
|
+
},
|
|
2960
|
+
limit: {
|
|
2961
|
+
type: "number",
|
|
2962
|
+
description: "Max tasks to load when building counts (server cap 10000)."
|
|
2963
|
+
}
|
|
2964
|
+
},
|
|
2965
|
+
additionalProperties: false,
|
|
2966
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
2967
|
+
};
|
|
2669
2968
|
var commandCenterGetSchema = {
|
|
2670
2969
|
type: "object",
|
|
2671
2970
|
properties: {
|
|
@@ -2815,9 +3114,14 @@ function createCommandCenterTools(config) {
|
|
|
2815
3114
|
return [
|
|
2816
3115
|
mk(
|
|
2817
3116
|
"agent_os_command_center_get",
|
|
2818
|
-
"Fetch the unified Command Center rollup
|
|
3117
|
+
"Fetch the unified Command Center rollup (includes countSnapshot \u2014 canonical badge counts). Same aggregate as the browser Command Center.",
|
|
2819
3118
|
commandCenterGetSchema
|
|
2820
3119
|
),
|
|
3120
|
+
mk(
|
|
3121
|
+
"agent_os_command_center_dashboard_contract_get",
|
|
3122
|
+
"Slim dashboard contract for runtime verification: countSnapshot, packageVersionHealth, runtime capacity, activePlanRollups \u2014 no graph/hierarchy.",
|
|
3123
|
+
commandCenterDashboardContractSchema
|
|
3124
|
+
),
|
|
2821
3125
|
mk(
|
|
2822
3126
|
"agent_os_task_next_action",
|
|
2823
3127
|
"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.",
|
|
@@ -2872,7 +3176,9 @@ var plugin = {
|
|
|
2872
3176
|
api.registerTool(tool);
|
|
2873
3177
|
}
|
|
2874
3178
|
registerAgentOsContinuityGuidanceHook({ api, config });
|
|
3179
|
+
registerTelegramReplyContextHooks({ api, config });
|
|
2875
3180
|
registerRuntimeSkillManifestHook({ api, config });
|
|
3181
|
+
registerTelegramToolErrorFilterHook({ api, config });
|
|
2876
3182
|
if (config.enableSessionLifecycle && typeof api.on === "function") {
|
|
2877
3183
|
const sessionIds = /* @__PURE__ */ new Map();
|
|
2878
3184
|
const keyFor = (event, ctx) => String(event?.sessionKey || ctx?.sessionKey || event?.sessionId || ctx?.sessionId || "");
|