@kynver-app/openclaw-agent-os 0.1.31 → 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 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
  "",
@@ -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 = { type: "string", enum: taskPriorityValues };
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
+ };
2330
2607
  var taskExecutor = { type: "string", enum: taskExecutorValues };
2331
2608
  var taskEventType = { type: "string", enum: taskEventTypeValues };
2332
2609
  var artifactVisibility = { type: "string", enum: artifactVisibilityValues };
@@ -2347,6 +2624,7 @@ var createTaskSchema = {
2347
2624
  title: { type: "string", description: "Short task title." },
2348
2625
  description: { type: "string" },
2349
2626
  priority: taskPriority,
2627
+ priorityEscalationReason,
2350
2628
  executor: taskExecutor,
2351
2629
  executorRef: { type: "string" },
2352
2630
  parentTaskId: { type: "string" },
@@ -2667,6 +2945,26 @@ var slugField = {
2667
2945
  type: "string",
2668
2946
  description: "AgentOS workspace slug. Omit to use the account's primary AgentOS workspace."
2669
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
+ };
2670
2968
  var commandCenterGetSchema = {
2671
2969
  type: "object",
2672
2970
  properties: {
@@ -2816,9 +3114,14 @@ function createCommandCenterTools(config) {
2816
3114
  return [
2817
3115
  mk(
2818
3116
  "agent_os_command_center_get",
2819
- "Fetch the unified Command Center rollup for the AgentOS workspace: plan rollups, project hierarchy, action-required items, DQ inbox, goals, review lanes, and harness summaries \u2014 the same aggregate the browser Command Center uses.",
3117
+ "Fetch the unified Command Center rollup (includes countSnapshot \u2014 canonical badge counts). Same aggregate as the browser Command Center.",
2820
3118
  commandCenterGetSchema
2821
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
+ ),
2822
3125
  mk(
2823
3126
  "agent_os_task_next_action",
2824
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.",
@@ -2873,7 +3176,9 @@ var plugin = {
2873
3176
  api.registerTool(tool);
2874
3177
  }
2875
3178
  registerAgentOsContinuityGuidanceHook({ api, config });
3179
+ registerTelegramReplyContextHooks({ api, config });
2876
3180
  registerRuntimeSkillManifestHook({ api, config });
3181
+ registerTelegramToolErrorFilterHook({ api, config });
2877
3182
  if (config.enableSessionLifecycle && typeof api.on === "function") {
2878
3183
  const sessionIds = /* @__PURE__ */ new Map();
2879
3184
  const keyFor = (event, ctx) => String(event?.sessionKey || ctx?.sessionKey || event?.sessionId || ctx?.sessionId || "");