omnius 1.0.657 → 1.0.659
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 +558 -90
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -779939,6 +779939,438 @@ var init_telegram_vision_router = __esm({
|
|
|
779939
779939
|
}
|
|
779940
779940
|
});
|
|
779941
779941
|
|
|
779942
|
+
// packages/cli/src/tui/telegram-api-governor.ts
|
|
779943
|
+
function positiveInteger3(value2, fallback) {
|
|
779944
|
+
return Number.isFinite(value2) && value2 > 0 ? Math.max(1, Math.floor(value2)) : fallback;
|
|
779945
|
+
}
|
|
779946
|
+
function nonNegativeInteger(value2, fallback) {
|
|
779947
|
+
return Number.isFinite(value2) && value2 >= 0 ? Math.max(0, Math.floor(value2)) : fallback;
|
|
779948
|
+
}
|
|
779949
|
+
function parseArrayLength(value2) {
|
|
779950
|
+
if (Array.isArray(value2)) return value2.length;
|
|
779951
|
+
if (typeof value2 !== "string") return void 0;
|
|
779952
|
+
try {
|
|
779953
|
+
const parsed = JSON.parse(value2);
|
|
779954
|
+
return Array.isArray(parsed) ? parsed.length : void 0;
|
|
779955
|
+
} catch {
|
|
779956
|
+
return void 0;
|
|
779957
|
+
}
|
|
779958
|
+
}
|
|
779959
|
+
function telegramDeliveryMessageCost(method, body) {
|
|
779960
|
+
if (!TELEGRAM_DELIVERY_METHODS.has(method)) return 0;
|
|
779961
|
+
if (method === "sendMediaGroup") {
|
|
779962
|
+
return Math.max(1, parseArrayLength(body?.["media"]) ?? 1);
|
|
779963
|
+
}
|
|
779964
|
+
if (method === "copyMessages" || method === "forwardMessages") {
|
|
779965
|
+
return Math.max(1, parseArrayLength(body?.["message_ids"]) ?? 1);
|
|
779966
|
+
}
|
|
779967
|
+
return 1;
|
|
779968
|
+
}
|
|
779969
|
+
function telegramFloodWaitSeconds(value2) {
|
|
779970
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
779971
|
+
return void 0;
|
|
779972
|
+
}
|
|
779973
|
+
const response = value2;
|
|
779974
|
+
if (Number(response["error_code"]) !== 429) return void 0;
|
|
779975
|
+
const parameters = response["parameters"];
|
|
779976
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
|
|
779977
|
+
return void 0;
|
|
779978
|
+
}
|
|
779979
|
+
const seconds = Number(
|
|
779980
|
+
parameters["retry_after"]
|
|
779981
|
+
);
|
|
779982
|
+
return Number.isFinite(seconds) && seconds > 0 ? seconds : void 0;
|
|
779983
|
+
}
|
|
779984
|
+
function inferredGroupChat(chatId, chatType) {
|
|
779985
|
+
if (chatType) return chatType !== "private";
|
|
779986
|
+
if (typeof chatId === "number") return chatId < 0;
|
|
779987
|
+
return typeof chatId === "string" && /^-\d+$/.test(chatId) && Number(chatId) < 0;
|
|
779988
|
+
}
|
|
779989
|
+
function abortError(reason) {
|
|
779990
|
+
if (reason instanceof Error) return reason;
|
|
779991
|
+
const error = new Error(
|
|
779992
|
+
typeof reason === "string" && reason ? reason : "Telegram request aborted"
|
|
779993
|
+
);
|
|
779994
|
+
error.name = "AbortError";
|
|
779995
|
+
return error;
|
|
779996
|
+
}
|
|
779997
|
+
var TELEGRAM_DELIVERY_METHODS, TelegramApiGovernor;
|
|
779998
|
+
var init_telegram_api_governor = __esm({
|
|
779999
|
+
"packages/cli/src/tui/telegram-api-governor.ts"() {
|
|
780000
|
+
TELEGRAM_DELIVERY_METHODS = /* @__PURE__ */ new Set([
|
|
780001
|
+
"copyMessage",
|
|
780002
|
+
"copyMessages",
|
|
780003
|
+
"forwardMessage",
|
|
780004
|
+
"forwardMessages",
|
|
780005
|
+
"sendAnimation",
|
|
780006
|
+
"sendAudio",
|
|
780007
|
+
"sendChecklist",
|
|
780008
|
+
"sendContact",
|
|
780009
|
+
"sendDice",
|
|
780010
|
+
"sendDocument",
|
|
780011
|
+
"sendGame",
|
|
780012
|
+
"sendInvoice",
|
|
780013
|
+
"sendLivePhoto",
|
|
780014
|
+
"sendLocation",
|
|
780015
|
+
"sendMediaGroup",
|
|
780016
|
+
"sendMessage",
|
|
780017
|
+
"sendMessageDraft",
|
|
780018
|
+
"sendPaidMedia",
|
|
780019
|
+
"sendPhoto",
|
|
780020
|
+
"sendPoll",
|
|
780021
|
+
"sendSticker",
|
|
780022
|
+
"sendVenue",
|
|
780023
|
+
"sendVideo",
|
|
780024
|
+
"sendVideoNote",
|
|
780025
|
+
"sendVoice"
|
|
780026
|
+
]);
|
|
780027
|
+
TelegramApiGovernor = class {
|
|
780028
|
+
globalRequestsPerSecond;
|
|
780029
|
+
globalMessagesPerSecond;
|
|
780030
|
+
perChatMessageIntervalMs;
|
|
780031
|
+
groupMessagesPerMinute;
|
|
780032
|
+
maxConcurrentRequests;
|
|
780033
|
+
maxQueuedRequests;
|
|
780034
|
+
now;
|
|
780035
|
+
lanes = /* @__PURE__ */ new Map();
|
|
780036
|
+
laneOrder = [];
|
|
780037
|
+
nextLaneIndex = 0;
|
|
780038
|
+
nextRequestId = 1;
|
|
780039
|
+
queuedCount = 0;
|
|
780040
|
+
activeCount = 0;
|
|
780041
|
+
timer = null;
|
|
780042
|
+
stoppedReason = null;
|
|
780043
|
+
globalCooldownUntilMs = 0;
|
|
780044
|
+
chatCooldownUntilMs = /* @__PURE__ */ new Map();
|
|
780045
|
+
globalRequestStarts = [];
|
|
780046
|
+
globalMessageStarts = [];
|
|
780047
|
+
groupMessageStarts = /* @__PURE__ */ new Map();
|
|
780048
|
+
nextChatMessageAtMs = /* @__PURE__ */ new Map();
|
|
780049
|
+
constructor(options2 = {}) {
|
|
780050
|
+
this.globalRequestsPerSecond = positiveInteger3(
|
|
780051
|
+
options2.globalRequestsPerSecond,
|
|
780052
|
+
28
|
|
780053
|
+
);
|
|
780054
|
+
this.globalMessagesPerSecond = positiveInteger3(
|
|
780055
|
+
options2.globalMessagesPerSecond,
|
|
780056
|
+
28
|
|
780057
|
+
);
|
|
780058
|
+
this.perChatMessageIntervalMs = nonNegativeInteger(
|
|
780059
|
+
options2.perChatMessageIntervalMs,
|
|
780060
|
+
1050
|
|
780061
|
+
);
|
|
780062
|
+
this.groupMessagesPerMinute = positiveInteger3(
|
|
780063
|
+
options2.groupMessagesPerMinute,
|
|
780064
|
+
20
|
|
780065
|
+
);
|
|
780066
|
+
this.maxConcurrentRequests = positiveInteger3(
|
|
780067
|
+
options2.maxConcurrentRequests,
|
|
780068
|
+
8
|
|
780069
|
+
);
|
|
780070
|
+
this.maxQueuedRequests = positiveInteger3(options2.maxQueuedRequests, 2048);
|
|
780071
|
+
this.now = options2.now ?? Date.now;
|
|
780072
|
+
}
|
|
780073
|
+
run(request) {
|
|
780074
|
+
if (this.stoppedReason) return Promise.reject(this.stoppedReason);
|
|
780075
|
+
if (request.signal?.aborted) {
|
|
780076
|
+
return Promise.reject(abortError(request.signal.reason));
|
|
780077
|
+
}
|
|
780078
|
+
if (request.method === "getUpdates") return request.execute();
|
|
780079
|
+
if (this.queuedCount >= this.maxQueuedRequests) {
|
|
780080
|
+
return Promise.reject(
|
|
780081
|
+
new Error(
|
|
780082
|
+
`Telegram API governor queue is full (${this.maxQueuedRequests} requests)`
|
|
780083
|
+
)
|
|
780084
|
+
);
|
|
780085
|
+
}
|
|
780086
|
+
const chatKey = request.chatId === void 0 ? void 0 : String(request.chatId);
|
|
780087
|
+
const laneKey = chatKey === void 0 ? "control" : `chat:${chatKey}`;
|
|
780088
|
+
const messageCost = telegramDeliveryMessageCost(
|
|
780089
|
+
request.method,
|
|
780090
|
+
request.body
|
|
780091
|
+
);
|
|
780092
|
+
return new Promise((resolve92, reject) => {
|
|
780093
|
+
const pending2 = {
|
|
780094
|
+
...request,
|
|
780095
|
+
id: this.nextRequestId++,
|
|
780096
|
+
laneKey,
|
|
780097
|
+
messageCost,
|
|
780098
|
+
notBeforeMs: 0,
|
|
780099
|
+
resolve: resolve92,
|
|
780100
|
+
reject,
|
|
780101
|
+
queued: false,
|
|
780102
|
+
settled: false
|
|
780103
|
+
};
|
|
780104
|
+
if (request.signal) {
|
|
780105
|
+
pending2.abortListener = () => {
|
|
780106
|
+
if (pending2.settled) return;
|
|
780107
|
+
pending2.settled = true;
|
|
780108
|
+
if (pending2.queued) {
|
|
780109
|
+
pending2.queued = false;
|
|
780110
|
+
this.queuedCount = Math.max(0, this.queuedCount - 1);
|
|
780111
|
+
}
|
|
780112
|
+
reject(abortError(request.signal?.reason));
|
|
780113
|
+
this.pump();
|
|
780114
|
+
};
|
|
780115
|
+
request.signal.addEventListener("abort", pending2.abortListener, {
|
|
780116
|
+
once: true
|
|
780117
|
+
});
|
|
780118
|
+
}
|
|
780119
|
+
this.enqueue(pending2);
|
|
780120
|
+
this.pump();
|
|
780121
|
+
});
|
|
780122
|
+
}
|
|
780123
|
+
stop(reason = "Telegram API governor stopped") {
|
|
780124
|
+
if (this.stoppedReason) return;
|
|
780125
|
+
this.stoppedReason = new Error(reason);
|
|
780126
|
+
if (this.timer) clearTimeout(this.timer);
|
|
780127
|
+
this.timer = null;
|
|
780128
|
+
for (const queue of this.lanes.values()) {
|
|
780129
|
+
for (const pending2 of queue) {
|
|
780130
|
+
if (pending2.settled) continue;
|
|
780131
|
+
pending2.settled = true;
|
|
780132
|
+
pending2.signal?.removeEventListener(
|
|
780133
|
+
"abort",
|
|
780134
|
+
pending2.abortListener ?? (() => {
|
|
780135
|
+
})
|
|
780136
|
+
);
|
|
780137
|
+
pending2.reject(this.stoppedReason);
|
|
780138
|
+
}
|
|
780139
|
+
}
|
|
780140
|
+
this.lanes.clear();
|
|
780141
|
+
this.laneOrder = [];
|
|
780142
|
+
this.queuedCount = 0;
|
|
780143
|
+
}
|
|
780144
|
+
snapshot() {
|
|
780145
|
+
return {
|
|
780146
|
+
active: this.activeCount,
|
|
780147
|
+
queued: this.queuedCount,
|
|
780148
|
+
lanes: this.lanes.size,
|
|
780149
|
+
globalCooldownUntilMs: this.globalCooldownUntilMs,
|
|
780150
|
+
chatCooldowns: Object.fromEntries(this.chatCooldownUntilMs)
|
|
780151
|
+
};
|
|
780152
|
+
}
|
|
780153
|
+
enqueue(pending2, front = false) {
|
|
780154
|
+
let queue = this.lanes.get(pending2.laneKey);
|
|
780155
|
+
if (!queue) {
|
|
780156
|
+
queue = [];
|
|
780157
|
+
this.lanes.set(pending2.laneKey, queue);
|
|
780158
|
+
this.laneOrder.push(pending2.laneKey);
|
|
780159
|
+
}
|
|
780160
|
+
if (pending2.coalesceKey) {
|
|
780161
|
+
const replacedIndex = queue.findIndex(
|
|
780162
|
+
(item) => !item.settled && item.coalesceKey === pending2.coalesceKey
|
|
780163
|
+
);
|
|
780164
|
+
if (replacedIndex >= 0) {
|
|
780165
|
+
const replaced = queue.splice(replacedIndex, 1)[0];
|
|
780166
|
+
replaced.queued = false;
|
|
780167
|
+
replaced.settled = true;
|
|
780168
|
+
this.queuedCount = Math.max(0, this.queuedCount - 1);
|
|
780169
|
+
if (replaced.abortListener) {
|
|
780170
|
+
replaced.signal?.removeEventListener("abort", replaced.abortListener);
|
|
780171
|
+
}
|
|
780172
|
+
if (replaced.supersededValue) {
|
|
780173
|
+
replaced.resolve(replaced.supersededValue());
|
|
780174
|
+
} else {
|
|
780175
|
+
replaced.reject(new Error("Telegram API request was superseded"));
|
|
780176
|
+
}
|
|
780177
|
+
}
|
|
780178
|
+
}
|
|
780179
|
+
if (front) queue.unshift(pending2);
|
|
780180
|
+
else queue.push(pending2);
|
|
780181
|
+
pending2.queued = true;
|
|
780182
|
+
this.queuedCount += 1;
|
|
780183
|
+
}
|
|
780184
|
+
removeEmptyLane(laneKey) {
|
|
780185
|
+
const queue = this.lanes.get(laneKey);
|
|
780186
|
+
if (queue?.some((item) => !item.settled)) return;
|
|
780187
|
+
this.lanes.delete(laneKey);
|
|
780188
|
+
const index = this.laneOrder.indexOf(laneKey);
|
|
780189
|
+
if (index < 0) return;
|
|
780190
|
+
this.laneOrder.splice(index, 1);
|
|
780191
|
+
if (this.laneOrder.length === 0) this.nextLaneIndex = 0;
|
|
780192
|
+
else if (index < this.nextLaneIndex) this.nextLaneIndex -= 1;
|
|
780193
|
+
this.nextLaneIndex %= Math.max(1, this.laneOrder.length);
|
|
780194
|
+
}
|
|
780195
|
+
pruneHistory(history, cutoff) {
|
|
780196
|
+
let remove = 0;
|
|
780197
|
+
while (remove < history.length && history[remove] <= cutoff) remove += 1;
|
|
780198
|
+
if (remove > 0) history.splice(0, remove);
|
|
780199
|
+
}
|
|
780200
|
+
windowReadyAt(history, now2, windowMs, limit2, cost) {
|
|
780201
|
+
this.pruneHistory(history, now2 - windowMs);
|
|
780202
|
+
const needed = history.length + cost - limit2;
|
|
780203
|
+
if (needed <= 0) return now2;
|
|
780204
|
+
return history[Math.min(history.length - 1, needed - 1)] + windowMs + 1;
|
|
780205
|
+
}
|
|
780206
|
+
requestReadyAt(pending2, now2) {
|
|
780207
|
+
let readyAt = Math.max(pending2.notBeforeMs, this.globalCooldownUntilMs);
|
|
780208
|
+
const chatKey = pending2.chatId === void 0 ? void 0 : String(pending2.chatId);
|
|
780209
|
+
if (chatKey !== void 0) {
|
|
780210
|
+
const cooldownUntil = this.chatCooldownUntilMs.get(chatKey) ?? 0;
|
|
780211
|
+
if (cooldownUntil <= now2) this.chatCooldownUntilMs.delete(chatKey);
|
|
780212
|
+
readyAt = Math.max(readyAt, cooldownUntil);
|
|
780213
|
+
}
|
|
780214
|
+
readyAt = Math.max(
|
|
780215
|
+
readyAt,
|
|
780216
|
+
this.windowReadyAt(
|
|
780217
|
+
this.globalRequestStarts,
|
|
780218
|
+
now2,
|
|
780219
|
+
1e3,
|
|
780220
|
+
this.globalRequestsPerSecond,
|
|
780221
|
+
1
|
|
780222
|
+
)
|
|
780223
|
+
);
|
|
780224
|
+
if (pending2.messageCost <= 0) return readyAt;
|
|
780225
|
+
readyAt = Math.max(
|
|
780226
|
+
readyAt,
|
|
780227
|
+
this.windowReadyAt(
|
|
780228
|
+
this.globalMessageStarts,
|
|
780229
|
+
now2,
|
|
780230
|
+
1e3,
|
|
780231
|
+
this.globalMessagesPerSecond,
|
|
780232
|
+
pending2.messageCost
|
|
780233
|
+
)
|
|
780234
|
+
);
|
|
780235
|
+
if (chatKey !== void 0) {
|
|
780236
|
+
const nextChatAt = this.nextChatMessageAtMs.get(chatKey) ?? 0;
|
|
780237
|
+
if (nextChatAt <= now2) this.nextChatMessageAtMs.delete(chatKey);
|
|
780238
|
+
readyAt = Math.max(readyAt, nextChatAt);
|
|
780239
|
+
if (inferredGroupChat(pending2.chatId, pending2.chatType)) {
|
|
780240
|
+
const groupHistory = this.groupMessageStarts.get(chatKey) ?? [];
|
|
780241
|
+
const groupReadyAt = this.windowReadyAt(
|
|
780242
|
+
groupHistory,
|
|
780243
|
+
now2,
|
|
780244
|
+
6e4,
|
|
780245
|
+
this.groupMessagesPerMinute,
|
|
780246
|
+
pending2.messageCost
|
|
780247
|
+
);
|
|
780248
|
+
if (groupHistory.length > 0) {
|
|
780249
|
+
this.groupMessageStarts.set(chatKey, groupHistory);
|
|
780250
|
+
} else {
|
|
780251
|
+
this.groupMessageStarts.delete(chatKey);
|
|
780252
|
+
}
|
|
780253
|
+
readyAt = Math.max(readyAt, groupReadyAt);
|
|
780254
|
+
}
|
|
780255
|
+
}
|
|
780256
|
+
return readyAt;
|
|
780257
|
+
}
|
|
780258
|
+
reserve(pending2, now2) {
|
|
780259
|
+
this.globalRequestStarts.push(now2);
|
|
780260
|
+
if (pending2.messageCost <= 0) return;
|
|
780261
|
+
for (let index = 0; index < pending2.messageCost; index++) {
|
|
780262
|
+
this.globalMessageStarts.push(now2);
|
|
780263
|
+
}
|
|
780264
|
+
if (pending2.chatId === void 0) return;
|
|
780265
|
+
const chatKey = String(pending2.chatId);
|
|
780266
|
+
this.nextChatMessageAtMs.set(chatKey, now2 + this.perChatMessageIntervalMs);
|
|
780267
|
+
if (!inferredGroupChat(pending2.chatId, pending2.chatType)) return;
|
|
780268
|
+
const groupHistory = this.groupMessageStarts.get(chatKey) ?? [];
|
|
780269
|
+
for (let index = 0; index < pending2.messageCost; index++) {
|
|
780270
|
+
groupHistory.push(now2);
|
|
780271
|
+
}
|
|
780272
|
+
this.groupMessageStarts.set(chatKey, groupHistory);
|
|
780273
|
+
}
|
|
780274
|
+
nextReadyRequest(now2) {
|
|
780275
|
+
if (this.laneOrder.length === 0) return {};
|
|
780276
|
+
let nextWakeMs = Number.POSITIVE_INFINITY;
|
|
780277
|
+
const laneCount = this.laneOrder.length;
|
|
780278
|
+
for (let offset = 0; offset < laneCount; offset++) {
|
|
780279
|
+
const index = (this.nextLaneIndex + offset) % laneCount;
|
|
780280
|
+
const laneKey = this.laneOrder[index];
|
|
780281
|
+
const queue = this.lanes.get(laneKey);
|
|
780282
|
+
while (queue?.[0]?.settled) queue.shift();
|
|
780283
|
+
const pending2 = queue?.[0];
|
|
780284
|
+
if (!pending2) {
|
|
780285
|
+
this.removeEmptyLane(laneKey);
|
|
780286
|
+
return this.nextReadyRequest(now2);
|
|
780287
|
+
}
|
|
780288
|
+
const readyAt = this.requestReadyAt(pending2, now2);
|
|
780289
|
+
nextWakeMs = Math.min(nextWakeMs, readyAt);
|
|
780290
|
+
if (readyAt > now2) continue;
|
|
780291
|
+
queue.shift();
|
|
780292
|
+
pending2.queued = false;
|
|
780293
|
+
this.queuedCount = Math.max(0, this.queuedCount - 1);
|
|
780294
|
+
this.nextLaneIndex = this.laneOrder.length === 0 ? 0 : (index + 1) % this.laneOrder.length;
|
|
780295
|
+
this.removeEmptyLane(laneKey);
|
|
780296
|
+
return { pending: pending2 };
|
|
780297
|
+
}
|
|
780298
|
+
return {
|
|
780299
|
+
nextWakeMs: Number.isFinite(nextWakeMs) ? nextWakeMs : void 0
|
|
780300
|
+
};
|
|
780301
|
+
}
|
|
780302
|
+
pump() {
|
|
780303
|
+
if (this.stoppedReason) return;
|
|
780304
|
+
if (this.timer) {
|
|
780305
|
+
clearTimeout(this.timer);
|
|
780306
|
+
this.timer = null;
|
|
780307
|
+
}
|
|
780308
|
+
while (this.activeCount < this.maxConcurrentRequests) {
|
|
780309
|
+
const now2 = this.now();
|
|
780310
|
+
const { pending: pending2, nextWakeMs } = this.nextReadyRequest(now2);
|
|
780311
|
+
if (!pending2) {
|
|
780312
|
+
if (nextWakeMs !== void 0 && this.queuedCount > 0) {
|
|
780313
|
+
this.timer = setTimeout(
|
|
780314
|
+
() => {
|
|
780315
|
+
this.timer = null;
|
|
780316
|
+
this.pump();
|
|
780317
|
+
},
|
|
780318
|
+
Math.max(1, nextWakeMs - now2)
|
|
780319
|
+
);
|
|
780320
|
+
}
|
|
780321
|
+
return;
|
|
780322
|
+
}
|
|
780323
|
+
if (pending2.settled) continue;
|
|
780324
|
+
this.reserve(pending2, now2);
|
|
780325
|
+
this.activeCount += 1;
|
|
780326
|
+
void this.execute(pending2);
|
|
780327
|
+
}
|
|
780328
|
+
}
|
|
780329
|
+
async execute(pending2) {
|
|
780330
|
+
try {
|
|
780331
|
+
const value2 = await pending2.execute();
|
|
780332
|
+
const floodWait = pending2.floodWaitSeconds?.(value2) ?? telegramFloodWaitSeconds(value2);
|
|
780333
|
+
if (floodWait !== void 0) {
|
|
780334
|
+
const retryAt = this.now() + Math.ceil(floodWait * 1e3);
|
|
780335
|
+
if (pending2.chatId === void 0) {
|
|
780336
|
+
this.globalCooldownUntilMs = Math.max(
|
|
780337
|
+
this.globalCooldownUntilMs,
|
|
780338
|
+
retryAt
|
|
780339
|
+
);
|
|
780340
|
+
} else {
|
|
780341
|
+
const chatKey = String(pending2.chatId);
|
|
780342
|
+
this.chatCooldownUntilMs.set(
|
|
780343
|
+
chatKey,
|
|
780344
|
+
Math.max(this.chatCooldownUntilMs.get(chatKey) ?? 0, retryAt)
|
|
780345
|
+
);
|
|
780346
|
+
}
|
|
780347
|
+
if (pending2.retryOnFlood !== false && !pending2.signal?.aborted) {
|
|
780348
|
+
pending2.notBeforeMs = retryAt;
|
|
780349
|
+
this.enqueue(pending2, true);
|
|
780350
|
+
return;
|
|
780351
|
+
}
|
|
780352
|
+
}
|
|
780353
|
+
if (!pending2.settled) {
|
|
780354
|
+
pending2.settled = true;
|
|
780355
|
+
pending2.resolve(value2);
|
|
780356
|
+
}
|
|
780357
|
+
} catch (error) {
|
|
780358
|
+
if (!pending2.settled) {
|
|
780359
|
+
pending2.settled = true;
|
|
780360
|
+
pending2.reject(error);
|
|
780361
|
+
}
|
|
780362
|
+
} finally {
|
|
780363
|
+
if (pending2.settled && pending2.abortListener) {
|
|
780364
|
+
pending2.signal?.removeEventListener("abort", pending2.abortListener);
|
|
780365
|
+
}
|
|
780366
|
+
this.activeCount = Math.max(0, this.activeCount - 1);
|
|
780367
|
+
this.pump();
|
|
780368
|
+
}
|
|
780369
|
+
}
|
|
780370
|
+
};
|
|
780371
|
+
}
|
|
780372
|
+
});
|
|
780373
|
+
|
|
779942
780374
|
// packages/cli/src/tui/vision-ingress.ts
|
|
779943
780375
|
var vision_ingress_exports = {};
|
|
779944
780376
|
__export(vision_ingress_exports, {
|
|
@@ -782719,6 +783151,7 @@ var init_telegram_bridge = __esm({
|
|
|
782719
783151
|
init_telegram_social_event_log();
|
|
782720
783152
|
init_dist();
|
|
782721
783153
|
init_telegram_vision_router();
|
|
783154
|
+
init_telegram_api_governor();
|
|
782722
783155
|
TELEGRAM_TOOL_ACTION_GROUPS = [
|
|
782723
783156
|
"read",
|
|
782724
783157
|
"message",
|
|
@@ -783366,11 +783799,14 @@ Telegram link integrity contract:
|
|
|
783366
783799
|
reminder: { limit: 20, windowMs: 24 * 60 * 6e4 }
|
|
783367
783800
|
};
|
|
783368
783801
|
TelegramBridge = class _TelegramBridge {
|
|
783369
|
-
constructor(botToken, onMessage, agentConfig, repoRoot, toolPolicyConfig) {
|
|
783802
|
+
constructor(botToken, onMessage, agentConfig, repoRoot, toolPolicyConfig, telegramApiGovernorOptions) {
|
|
783370
783803
|
this.botToken = botToken;
|
|
783371
783804
|
this.onMessage = onMessage;
|
|
783372
783805
|
this.agentConfig = agentConfig;
|
|
783373
783806
|
this.repoRoot = repoRoot;
|
|
783807
|
+
this.telegramApiGovernor = new TelegramApiGovernor(
|
|
783808
|
+
telegramApiGovernorOptions
|
|
783809
|
+
);
|
|
783374
783810
|
this.toolPolicyConfig = toolPolicyConfig;
|
|
783375
783811
|
this.telegramToolPolicy = resolveSettings(repoRoot || ".").telegramToolPolicy ?? {};
|
|
783376
783812
|
this.mediaCacheDir = resolve83(
|
|
@@ -783421,6 +783857,10 @@ Telegram link integrity contract:
|
|
|
783421
783857
|
repoRoot;
|
|
783422
783858
|
polling = false;
|
|
783423
783859
|
abortController = null;
|
|
783860
|
+
/** One fair outbound admission queue shared by every chat on this bot. */
|
|
783861
|
+
telegramApiGovernor;
|
|
783862
|
+
/** Chat types learned from inbound updates improve group quota accounting. */
|
|
783863
|
+
telegramKnownChatTypes = /* @__PURE__ */ new Map();
|
|
783424
783864
|
pollLoopPromise = null;
|
|
783425
783865
|
pollFatalNotified = false;
|
|
783426
783866
|
lastUpdateId = 0;
|
|
@@ -784978,11 +785418,11 @@ ${message2}`)
|
|
|
784978
785418
|
for (const item of subAgent.pendingIntakeRecords.splice(0)) {
|
|
784979
785419
|
pendingById.set(item.intake.inputId, item);
|
|
784980
785420
|
}
|
|
784981
|
-
|
|
784982
|
-
for (const item of retainedSteeringIntakes.values()) {
|
|
785421
|
+
subAgent.retainedSteeringIntakes ??= /* @__PURE__ */ new Map();
|
|
785422
|
+
for (const item of subAgent.retainedSteeringIntakes.values()) {
|
|
784983
785423
|
pendingById.set(item.intake.inputId, item);
|
|
784984
785424
|
}
|
|
784985
|
-
retainedSteeringIntakes.clear();
|
|
785425
|
+
subAgent.retainedSteeringIntakes.clear();
|
|
784986
785426
|
const pending2 = [...pendingById.values()];
|
|
784987
785427
|
if (pending2.length === 0) return;
|
|
784988
785428
|
for (const item of pending2) {
|
|
@@ -791918,7 +792358,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
|
|
|
791918
792358
|
}
|
|
791919
792359
|
const retryAfter = Number(result?.["parameters"]?.["retry_after"]);
|
|
791920
792360
|
if (Number.isFinite(retryAfter) && retryAfter > 0) {
|
|
791921
|
-
return Math.
|
|
792361
|
+
return Math.ceil(retryAfter * 1e3);
|
|
791922
792362
|
}
|
|
791923
792363
|
return [500, 1e3, 2e3][Math.min(attempt, 2)];
|
|
791924
792364
|
}
|
|
@@ -791973,6 +792413,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
|
|
|
791973
792413
|
this.state.active = false;
|
|
791974
792414
|
this.abortController?.abort();
|
|
791975
792415
|
this.abortController = null;
|
|
792416
|
+
this.telegramApiGovernor.stop("Telegram bridge stopped");
|
|
791976
792417
|
if (this.mediaCacheCleanupTimer) {
|
|
791977
792418
|
clearInterval(this.mediaCacheCleanupTimer);
|
|
791978
792419
|
this.mediaCacheCleanupTimer = null;
|
|
@@ -792354,6 +792795,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
|
|
|
792354
792795
|
});
|
|
792355
792796
|
if (result.error_code === 400 && result.description?.includes("not modified"))
|
|
792356
792797
|
return true;
|
|
792798
|
+
if (result.error_code === 429) return false;
|
|
792357
792799
|
if (result.ok === false)
|
|
792358
792800
|
throw new Error(
|
|
792359
792801
|
String(result.description || "Telegram editMessageText failed")
|
|
@@ -796260,9 +796702,7 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
796260
796702
|
enum: exposedActions,
|
|
796261
796703
|
description: [
|
|
796262
796704
|
"Exact Telegram operation from this enum.",
|
|
796263
|
-
...moderationDescriptions.map(
|
|
796264
|
-
(description) => `${description}.`
|
|
796265
|
-
)
|
|
796705
|
+
...moderationDescriptions.map((description) => `${description}.`)
|
|
796266
796706
|
].join(" ")
|
|
796267
796707
|
},
|
|
796268
796708
|
target: {
|
|
@@ -797106,7 +797546,9 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
797106
797546
|
);
|
|
797107
797547
|
}
|
|
797108
797548
|
if (!Number.isSafeInteger(targetUserId) || targetUserId <= 0) {
|
|
797109
|
-
throw new Error(
|
|
797549
|
+
throw new Error(
|
|
797550
|
+
"A positive numeric Telegram target user_id is required."
|
|
797551
|
+
);
|
|
797110
797552
|
}
|
|
797111
797553
|
const group = await this.requireTelegramModerationGroup(chatId);
|
|
797112
797554
|
const rights = await this.getBotChatRights(chatId, true);
|
|
@@ -797145,7 +797587,9 @@ Scoped workspace: ${scopedRoot}`,
|
|
|
797145
797587
|
detail: "The exact action is already staged; no duplicate prompt was sent."
|
|
797146
797588
|
};
|
|
797147
797589
|
}
|
|
797148
|
-
const conflicting = [
|
|
797590
|
+
const conflicting = [
|
|
797591
|
+
...this.telegramPendingModerationApprovals.values()
|
|
797592
|
+
].find(
|
|
797149
797593
|
(candidate) => candidate.state === "pending" && String(candidate.action.chatId) === String(chatId) && candidate.expiresAtMs > Date.now()
|
|
797150
797594
|
);
|
|
797151
797595
|
if (conflicting) {
|
|
@@ -797473,10 +797917,7 @@ ${this.quoteTelegramContextBlock(msg.text, 800)}`,
|
|
|
797473
797917
|
}
|
|
797474
797918
|
try {
|
|
797475
797919
|
await this.requireTelegramModerationGroup(approval.action.chatId);
|
|
797476
|
-
const rights = await this.getBotChatRights(
|
|
797477
|
-
approval.action.chatId,
|
|
797478
|
-
true
|
|
797479
|
-
);
|
|
797920
|
+
const rights = await this.getBotChatRights(approval.action.chatId, true);
|
|
797480
797921
|
if (!rights.isAdministrator || !rights.canRestrictMembers) {
|
|
797481
797922
|
throw new Error(
|
|
797482
797923
|
`Bot no longer has administrator can_restrict_members authority; status=${rights.status}.`
|
|
@@ -800166,26 +800607,22 @@ Content-Type: ${contentType}\r
|
|
|
800166
800607
|
`));
|
|
800167
800608
|
const body = Buffer.concat(parts);
|
|
800168
800609
|
const uploadUrl = `https://api.telegram.org/bot${this.botToken}/${method}`;
|
|
800169
|
-
const
|
|
800170
|
-
|
|
800171
|
-
|
|
800172
|
-
|
|
800173
|
-
|
|
800174
|
-
|
|
800175
|
-
|
|
800176
|
-
|
|
800177
|
-
|
|
800178
|
-
|
|
800179
|
-
|
|
800180
|
-
|
|
800181
|
-
|
|
800182
|
-
|
|
800183
|
-
|
|
800184
|
-
|
|
800185
|
-
if (!canRetry) break;
|
|
800186
|
-
const waitMs = Math.min(retryAfterSec * 1e3, PER_RETRY_WAIT_CAP_MS);
|
|
800187
|
-
await new Promise((r2) => setTimeout(r2, waitMs));
|
|
800188
|
-
}
|
|
800610
|
+
const result = await this.governedTelegramApiRequest(
|
|
800611
|
+
method,
|
|
800612
|
+
{ chat_id: chatId },
|
|
800613
|
+
async () => {
|
|
800614
|
+
const res = await fetch(uploadUrl, {
|
|
800615
|
+
method: "POST",
|
|
800616
|
+
headers: {
|
|
800617
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
800618
|
+
"Content-Length": String(body.length)
|
|
800619
|
+
},
|
|
800620
|
+
body,
|
|
800621
|
+
signal: this.abortController?.signal
|
|
800622
|
+
});
|
|
800623
|
+
return await res.json();
|
|
800624
|
+
}
|
|
800625
|
+
);
|
|
800189
800626
|
if (result.ok) {
|
|
800190
800627
|
this.state.messagesSent++;
|
|
800191
800628
|
const outboundMessageId = result.result?.message_id ?? null;
|
|
@@ -800494,18 +800931,21 @@ Content-Type: ${mimeForPath(pathOrFileId, field === "photo" ? "image" : "video")
|
|
|
800494
800931
|
parts.push(Buffer.from(`--${boundary}--\r
|
|
800495
800932
|
`));
|
|
800496
800933
|
const body = Buffer.concat(parts);
|
|
800497
|
-
|
|
800498
|
-
|
|
800499
|
-
|
|
800500
|
-
|
|
800501
|
-
|
|
800502
|
-
|
|
800503
|
-
|
|
800504
|
-
|
|
800505
|
-
|
|
800506
|
-
|
|
800507
|
-
|
|
800508
|
-
|
|
800934
|
+
return this.governedTelegramApiRequest(method, { ...fields }, async () => {
|
|
800935
|
+
const res = await fetch(
|
|
800936
|
+
`https://api.telegram.org/bot${this.botToken}/${method}`,
|
|
800937
|
+
{
|
|
800938
|
+
method: "POST",
|
|
800939
|
+
headers: {
|
|
800940
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
800941
|
+
"Content-Length": String(body.length)
|
|
800942
|
+
},
|
|
800943
|
+
body,
|
|
800944
|
+
signal: this.abortController?.signal
|
|
800945
|
+
}
|
|
800946
|
+
);
|
|
800947
|
+
return await res.json();
|
|
800948
|
+
});
|
|
800509
800949
|
}
|
|
800510
800950
|
/**
|
|
800511
800951
|
* Bot API 10.0: send a message to another bot by username.
|
|
@@ -800816,15 +801256,22 @@ ${caption}\r
|
|
|
800816
801256
|
`));
|
|
800817
801257
|
const body = Buffer.concat(parts);
|
|
800818
801258
|
const url = `https://api.telegram.org/bot${this.botToken}/${method}`;
|
|
800819
|
-
const
|
|
800820
|
-
method
|
|
800821
|
-
|
|
800822
|
-
|
|
800823
|
-
|
|
800824
|
-
|
|
800825
|
-
|
|
800826
|
-
|
|
800827
|
-
|
|
801259
|
+
const result = await this.governedTelegramApiRequest(
|
|
801260
|
+
method,
|
|
801261
|
+
{ chat_id: chatId },
|
|
801262
|
+
async () => {
|
|
801263
|
+
const res = await fetch(url, {
|
|
801264
|
+
method: "POST",
|
|
801265
|
+
headers: {
|
|
801266
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
801267
|
+
"Content-Length": String(body.length)
|
|
801268
|
+
},
|
|
801269
|
+
body,
|
|
801270
|
+
signal: this.abortController?.signal
|
|
801271
|
+
});
|
|
801272
|
+
return await res.json();
|
|
801273
|
+
}
|
|
801274
|
+
);
|
|
800828
801275
|
if (result.ok) {
|
|
800829
801276
|
this.state.messagesSent++;
|
|
800830
801277
|
return result.result?.message_id ?? null;
|
|
@@ -800898,6 +801345,7 @@ ${caption}\r
|
|
|
800898
801345
|
}
|
|
800899
801346
|
const msg = normalizeTelegramUpdate(update2);
|
|
800900
801347
|
if (!msg) continue;
|
|
801348
|
+
this.telegramKnownChatTypes.set(String(msg.chatId), msg.chatType);
|
|
800901
801349
|
this.persistTelegramRawMessage(update2, msg);
|
|
800902
801350
|
this.state.messagesReceived++;
|
|
800903
801351
|
const isAdmin = this.adminUserId ? String(msg.fromUserId) === this.adminUserId || msg.username === this.adminUserId : false;
|
|
@@ -800970,44 +801418,64 @@ ${caption}\r
|
|
|
800970
801418
|
if (raw >= floor && raw <= 3e5) return raw;
|
|
800971
801419
|
return null;
|
|
800972
801420
|
}
|
|
800973
|
-
|
|
800974
|
-
|
|
801421
|
+
telegramApiChatId(body) {
|
|
801422
|
+
const value2 = body?.["chat_id"];
|
|
801423
|
+
return typeof value2 === "number" || typeof value2 === "string" && value2.length > 0 ? value2 : void 0;
|
|
801424
|
+
}
|
|
801425
|
+
telegramApiChatType(chatId) {
|
|
801426
|
+
return chatId === void 0 ? void 0 : this.telegramKnownChatTypes.get(String(chatId));
|
|
801427
|
+
}
|
|
801428
|
+
async governedTelegramApiRequest(method, body, execute, options2 = {}) {
|
|
801429
|
+
const chatId = this.telegramApiChatId(body);
|
|
801430
|
+
return this.telegramApiGovernor.run({
|
|
801431
|
+
method,
|
|
801432
|
+
body,
|
|
801433
|
+
chatId,
|
|
801434
|
+
chatType: this.telegramApiChatType(chatId),
|
|
801435
|
+
execute,
|
|
801436
|
+
signal: this.abortController?.signal,
|
|
801437
|
+
retryOnFlood: options2.retryOnFlood,
|
|
801438
|
+
floodWaitSeconds: telegramFloodWaitSeconds,
|
|
801439
|
+
coalesceKey: options2.coalesceKey,
|
|
801440
|
+
supersededValue: options2.supersededValue
|
|
801441
|
+
});
|
|
801442
|
+
}
|
|
801443
|
+
/** Make a Telegram Bot API call through the per-bot fair governor. */
|
|
801444
|
+
async apiCall(method, body) {
|
|
800975
801445
|
const url = `https://api.telegram.org/bot${this.botToken}/${method}`;
|
|
800976
|
-
const options2 = {
|
|
800977
|
-
method: "POST",
|
|
800978
|
-
headers: { "Content-Type": "application/json" }
|
|
800979
|
-
};
|
|
800980
|
-
if (body) {
|
|
800981
|
-
options2.body = JSON.stringify(body);
|
|
800982
|
-
}
|
|
800983
801446
|
const isLongPoll = method === "getUpdates";
|
|
800984
|
-
|
|
800985
|
-
|
|
800986
|
-
|
|
800987
|
-
|
|
800988
|
-
|
|
800989
|
-
|
|
800990
|
-
|
|
800991
|
-
|
|
800992
|
-
|
|
800993
|
-
|
|
800994
|
-
|
|
800995
|
-
|
|
800996
|
-
|
|
800997
|
-
|
|
800998
|
-
|
|
800999
|
-
|
|
801000
|
-
|
|
801001
|
-
|
|
801002
|
-
|
|
801003
|
-
|
|
801004
|
-
|
|
801005
|
-
return
|
|
801447
|
+
return this.governedTelegramApiRequest(
|
|
801448
|
+
method,
|
|
801449
|
+
body,
|
|
801450
|
+
async () => {
|
|
801451
|
+
const request = {
|
|
801452
|
+
method: "POST",
|
|
801453
|
+
headers: { "Content-Type": "application/json" }
|
|
801454
|
+
};
|
|
801455
|
+
if (body) request.body = JSON.stringify(body);
|
|
801456
|
+
const timeoutFn = AbortSignal.timeout;
|
|
801457
|
+
const anyFn = AbortSignal.any;
|
|
801458
|
+
const bodyTimeout = typeof body?.["timeout"] === "number" ? body["timeout"] : void 0;
|
|
801459
|
+
const clientTimeoutMs = isLongPoll ? this.telegramLongPollClientTimeoutMs(bodyTimeout) : 3e4;
|
|
801460
|
+
const signals = [
|
|
801461
|
+
this.abortController?.signal,
|
|
801462
|
+
clientTimeoutMs && typeof timeoutFn === "function" ? timeoutFn(clientTimeoutMs) : void 0
|
|
801463
|
+
].filter(
|
|
801464
|
+
(signal) => signal instanceof AbortSignal
|
|
801465
|
+
);
|
|
801466
|
+
request.signal = typeof anyFn === "function" && signals.length > 1 ? anyFn(signals) : signals[0];
|
|
801467
|
+
const response = await fetch(url, request);
|
|
801468
|
+
return await response.json();
|
|
801469
|
+
},
|
|
801470
|
+
// Progressive edits are disposable. A flood response still updates the
|
|
801471
|
+
// chat cooldown, but replaying stale partial text would block inference
|
|
801472
|
+
// and could overwrite a newer final reply.
|
|
801473
|
+
{
|
|
801474
|
+
retryOnFlood: method !== "editMessageText",
|
|
801475
|
+
coalesceKey: method === "editMessageText" && body?.["message_id"] !== void 0 ? `editMessageText:${String(body["chat_id"])}:${String(body["message_id"])}` : void 0,
|
|
801476
|
+
supersededValue: method === "editMessageText" ? () => ({ ok: true, result: true, omitted_by_governor: true }) : void 0
|
|
801006
801477
|
}
|
|
801007
|
-
|
|
801008
|
-
return this.apiCall(method, body, _retryDepth + 1);
|
|
801009
|
-
}
|
|
801010
|
-
return data;
|
|
801478
|
+
);
|
|
801011
801479
|
}
|
|
801012
801480
|
};
|
|
801013
801481
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.659",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.659",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED