omnius 1.0.114 → 1.0.115
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 +160 -4
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -619825,18 +619825,167 @@ ${retryText}`,
|
|
|
619825
619825
|
* in-flight promise, and on completion fire any queued trailing call.
|
|
619826
619826
|
*/
|
|
619827
619827
|
startCoalescedTelegramRouterCall(sessionKey, msg, toolContext) {
|
|
619828
|
-
const
|
|
619828
|
+
const HARD_DEADLINE_MS = 18e4;
|
|
619829
|
+
const inner = this.inferTelegramInteractionDecision(msg, toolContext);
|
|
619830
|
+
const promise = new Promise((resolve52, reject) => {
|
|
619831
|
+
let settled = false;
|
|
619832
|
+
const guard = setTimeout(() => {
|
|
619833
|
+
if (settled) return;
|
|
619834
|
+
settled = true;
|
|
619835
|
+
reject(new Error("router-coalescer: hard deadline exceeded (180s); inner inference did not settle"));
|
|
619836
|
+
}, HARD_DEADLINE_MS);
|
|
619837
|
+
if (typeof guard.unref === "function") guard.unref();
|
|
619838
|
+
inner.then(
|
|
619839
|
+
(v) => {
|
|
619840
|
+
if (settled) return;
|
|
619841
|
+
settled = true;
|
|
619842
|
+
clearTimeout(guard);
|
|
619843
|
+
resolve52(v);
|
|
619844
|
+
},
|
|
619845
|
+
(e2) => {
|
|
619846
|
+
if (settled) return;
|
|
619847
|
+
settled = true;
|
|
619848
|
+
clearTimeout(guard);
|
|
619849
|
+
reject(e2);
|
|
619850
|
+
}
|
|
619851
|
+
);
|
|
619852
|
+
});
|
|
619829
619853
|
this.telegramRouterSessionState.set(sessionKey, { inFlight: promise });
|
|
619830
619854
|
const onSettled = () => {
|
|
619831
|
-
|
|
619832
|
-
|
|
619855
|
+
let state;
|
|
619856
|
+
try {
|
|
619857
|
+
state = this.telegramRouterSessionState.get(sessionKey);
|
|
619858
|
+
this.telegramRouterSessionState.delete(sessionKey);
|
|
619859
|
+
} catch {
|
|
619860
|
+
state = void 0;
|
|
619861
|
+
}
|
|
619833
619862
|
if (!state?.trailing) return;
|
|
619834
619863
|
const { msg: nextMsg, toolContext: nextCtx, resolve: resolve52, reject } = state.trailing;
|
|
619835
|
-
|
|
619864
|
+
try {
|
|
619865
|
+
this.startCoalescedTelegramRouterCall(sessionKey, nextMsg, nextCtx).then(resolve52, reject);
|
|
619866
|
+
} catch (err) {
|
|
619867
|
+
reject(err);
|
|
619868
|
+
}
|
|
619836
619869
|
};
|
|
619837
619870
|
promise.then(onSettled, onSettled);
|
|
619838
619871
|
return promise;
|
|
619839
619872
|
}
|
|
619873
|
+
/**
|
|
619874
|
+
* Forcibly cancel every in-flight + trailing router-coalescer entry.
|
|
619875
|
+
* Used on bridge stop() and by the watchdog if it detects the coalescer
|
|
619876
|
+
* map has grown unboundedly. Rejects every queued caller cleanly so they
|
|
619877
|
+
* surface the cancellation rather than waiting forever.
|
|
619878
|
+
*/
|
|
619879
|
+
cancelTelegramRouterSessionState(reason) {
|
|
619880
|
+
const err = new Error(`router-coalescer cancelled: ${reason}`);
|
|
619881
|
+
for (const [, state] of this.telegramRouterSessionState) {
|
|
619882
|
+
if (state.trailing) {
|
|
619883
|
+
try {
|
|
619884
|
+
state.trailing.reject(err);
|
|
619885
|
+
} catch {
|
|
619886
|
+
}
|
|
619887
|
+
}
|
|
619888
|
+
}
|
|
619889
|
+
this.telegramRouterSessionState.clear();
|
|
619890
|
+
}
|
|
619891
|
+
// ─────────────────────────────────────────────────────────────────
|
|
619892
|
+
// Sub-agent staleness watchdog
|
|
619893
|
+
// ─────────────────────────────────────────────────────────────────
|
|
619894
|
+
/** Interval handle for the periodic stale-sub-agent reaper. */
|
|
619895
|
+
telegramSubAgentWatchdogTimer = null;
|
|
619896
|
+
/**
|
|
619897
|
+
* Maximum wall-clock time a sub-agent may go without a visible-edit
|
|
619898
|
+
* progress event before the watchdog declares it stale and tears it
|
|
619899
|
+
* down. Tuned to be comfortably longer than the slowest healthy turn
|
|
619900
|
+
* (which is bounded by request_timeout = 5-15min per turn) but short
|
|
619901
|
+
* enough that a wedged sub-agent doesn't pin a chat for an entire day.
|
|
619902
|
+
*
|
|
619903
|
+
* Override with env var OMNIUS_TG_SUBAGENT_MAX_IDLE_MS for ops tuning.
|
|
619904
|
+
*/
|
|
619905
|
+
telegramSubAgentMaxIdleMs() {
|
|
619906
|
+
const raw = Number.parseInt(process.env["OMNIUS_TG_SUBAGENT_MAX_IDLE_MS"] ?? "", 10);
|
|
619907
|
+
if (Number.isFinite(raw) && raw >= 3e4 && raw <= 36e5) return raw;
|
|
619908
|
+
return 6e5;
|
|
619909
|
+
}
|
|
619910
|
+
/** Watchdog tick period — checked every 30s. */
|
|
619911
|
+
telegramSubAgentWatchdogIntervalMs() {
|
|
619912
|
+
return 3e4;
|
|
619913
|
+
}
|
|
619914
|
+
/**
|
|
619915
|
+
* Start the periodic stale-sub-agent reaper. Idempotent — safe to call
|
|
619916
|
+
* multiple times (no-op if already running). Stopped by stop() and on
|
|
619917
|
+
* SIGTERM via the cleanup chain.
|
|
619918
|
+
*/
|
|
619919
|
+
startTelegramSubAgentWatchdog() {
|
|
619920
|
+
if (this.telegramSubAgentWatchdogTimer) return;
|
|
619921
|
+
const tick = () => {
|
|
619922
|
+
try {
|
|
619923
|
+
this.reapStaleTelegramSubAgents();
|
|
619924
|
+
} catch (err) {
|
|
619925
|
+
this.tuiWrite(() => renderTelegramSubAgentError(
|
|
619926
|
+
"watchdog",
|
|
619927
|
+
`tick failed: ${err instanceof Error ? err.message : String(err)}`
|
|
619928
|
+
));
|
|
619929
|
+
}
|
|
619930
|
+
};
|
|
619931
|
+
this.telegramSubAgentWatchdogTimer = setInterval(tick, this.telegramSubAgentWatchdogIntervalMs());
|
|
619932
|
+
if (typeof this.telegramSubAgentWatchdogTimer.unref === "function") {
|
|
619933
|
+
this.telegramSubAgentWatchdogTimer.unref();
|
|
619934
|
+
}
|
|
619935
|
+
}
|
|
619936
|
+
/** Stop the periodic stale-sub-agent reaper. */
|
|
619937
|
+
stopTelegramSubAgentWatchdog() {
|
|
619938
|
+
if (this.telegramSubAgentWatchdogTimer) {
|
|
619939
|
+
clearInterval(this.telegramSubAgentWatchdogTimer);
|
|
619940
|
+
this.telegramSubAgentWatchdogTimer = null;
|
|
619941
|
+
}
|
|
619942
|
+
}
|
|
619943
|
+
/**
|
|
619944
|
+
* One watchdog pass: walk the sub-agent map; for each entry where the
|
|
619945
|
+
* last visible-edit progress event is older than maxIdle AND no completion
|
|
619946
|
+
* boundary has been seen, abort the runner and remove the entry. This is
|
|
619947
|
+
* the load-bearing fix for the runaway-sub-agent steady-state leak: a
|
|
619948
|
+
* runner that hangs (qwen3 think-stall, Ollama TCP wedge, lost stream)
|
|
619949
|
+
* otherwise pins the chat forever, because the finally{} in runSubAgent
|
|
619950
|
+
* never fires.
|
|
619951
|
+
*/
|
|
619952
|
+
reapStaleTelegramSubAgents() {
|
|
619953
|
+
const maxIdleMs = this.telegramSubAgentMaxIdleMs();
|
|
619954
|
+
const now = Date.now();
|
|
619955
|
+
const stale = [];
|
|
619956
|
+
for (const [sessionKey, agent] of this.subAgents) {
|
|
619957
|
+
if (agent.aborted) continue;
|
|
619958
|
+
const idle = agent.lastEditMs > 0 ? now - agent.lastEditMs : 0;
|
|
619959
|
+
if (idle <= maxIdleMs) continue;
|
|
619960
|
+
if (agent.completionBoundarySeen) continue;
|
|
619961
|
+
stale.push(sessionKey);
|
|
619962
|
+
}
|
|
619963
|
+
for (const sessionKey of stale) {
|
|
619964
|
+
const agent = this.subAgents.get(sessionKey);
|
|
619965
|
+
if (!agent) continue;
|
|
619966
|
+
agent.aborted = true;
|
|
619967
|
+
if (agent.typingInterval) {
|
|
619968
|
+
clearInterval(agent.typingInterval);
|
|
619969
|
+
agent.typingInterval = null;
|
|
619970
|
+
}
|
|
619971
|
+
try {
|
|
619972
|
+
agent.runner?.abort?.();
|
|
619973
|
+
} catch {
|
|
619974
|
+
}
|
|
619975
|
+
this.subAgents.delete(sessionKey);
|
|
619976
|
+
this.refreshActiveTelegramInteractionCount();
|
|
619977
|
+
this.tuiWrite(() => renderTelegramSubAgentEvent(
|
|
619978
|
+
agent.username,
|
|
619979
|
+
`watchdog: aborted stale sub-agent (idle ${Math.round((now - agent.lastEditMs) / 1e3)}s without completion)`
|
|
619980
|
+
));
|
|
619981
|
+
this.subAgentViewCallbacks?.onWrite(
|
|
619982
|
+
agent.viewId,
|
|
619983
|
+
`watchdog: sub-agent retired after ${Math.round((now - agent.lastEditMs) / 1e3)}s without a progress event`
|
|
619984
|
+
);
|
|
619985
|
+
this.subAgentViewCallbacks?.onStatus(agent.viewId, "failed");
|
|
619986
|
+
this.subAgentViewCallbacks?.onComplete(agent.viewId);
|
|
619987
|
+
}
|
|
619988
|
+
}
|
|
619840
619989
|
async inferTelegramInteractionDecision(msg, toolContext) {
|
|
619841
619990
|
const config = this.agentConfig;
|
|
619842
619991
|
const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
|
|
@@ -620434,6 +620583,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
|
|
|
620434
620583
|
this.polling = true;
|
|
620435
620584
|
this.pollFatalNotified = false;
|
|
620436
620585
|
this.abortController = new AbortController();
|
|
620586
|
+
this.startTelegramSubAgentWatchdog();
|
|
620437
620587
|
await this.prepareTelegramLongPolling();
|
|
620438
620588
|
try {
|
|
620439
620589
|
mkdirSync66(this.mediaCacheDir, { recursive: true });
|
|
@@ -620509,7 +620659,13 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
|
|
|
620509
620659
|
for (const [, agent] of this.subAgents) {
|
|
620510
620660
|
agent.aborted = true;
|
|
620511
620661
|
if (agent.typingInterval) clearInterval(agent.typingInterval);
|
|
620662
|
+
try {
|
|
620663
|
+
agent.runner?.abort?.();
|
|
620664
|
+
} catch {
|
|
620665
|
+
}
|
|
620512
620666
|
}
|
|
620667
|
+
this.stopTelegramSubAgentWatchdog();
|
|
620668
|
+
this.cancelTelegramRouterSessionState("bridge stop");
|
|
620513
620669
|
if (this.telegramSqliteDb && this.telegramSqliteDb !== false) {
|
|
620514
620670
|
try {
|
|
620515
620671
|
this.telegramSqliteDb.close();
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.115",
|
|
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.115",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED