alvin-bot 5.6.2 → 5.8.0
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/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -130
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -443
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -0
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1831
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
|
@@ -1,814 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sub-Agent System — Parallel Task Execution
|
|
3
|
-
*
|
|
4
|
-
* Spawns isolated AI workers that run in the background using the engine registry.
|
|
5
|
-
* Each sub-agent gets its own query call (not a persistent session).
|
|
6
|
-
* Results are stored and can be retrieved by the caller.
|
|
7
|
-
*/
|
|
8
|
-
import os from "os";
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
import { resolve, dirname } from "path";
|
|
11
|
-
import crypto from "crypto";
|
|
12
|
-
import { config } from "../config.js";
|
|
13
|
-
// ── File-based config (persistent, runtime-editable) ───────────────────
|
|
14
|
-
const DATA_DIR = process.env.ALVIN_DATA_DIR || resolve(os.homedir(), ".alvin-bot");
|
|
15
|
-
const CONFIG_FILE = resolve(DATA_DIR, "sub-agents.json");
|
|
16
|
-
const ABSOLUTE_MAX_AGENTS = 16; // Hard cap no matter what
|
|
17
|
-
const MAX_SUBAGENT_DEPTH = 2; // F2: hard cap on nested spawning
|
|
18
|
-
const DEFAULT_QUEUE_CAP = 20; // D3: default bounded-queue size
|
|
19
|
-
const ABSOLUTE_MAX_QUEUE = 200; // D3: absolute ceiling on queue length
|
|
20
|
-
let configCache = null;
|
|
21
|
-
function isValidVisibility(v) {
|
|
22
|
-
return v === "auto" || v === "banner" || v === "silent" || v === "live";
|
|
23
|
-
}
|
|
24
|
-
/** Resolve the initial default timeout from config.ts, which itself seeds
|
|
25
|
-
* from the SUBAGENT_TIMEOUT env var. -1 = unlimited. */
|
|
26
|
-
function seedDefaultTimeout() {
|
|
27
|
-
const raw = config.subAgentTimeout;
|
|
28
|
-
if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0)
|
|
29
|
-
return -1;
|
|
30
|
-
return Math.floor(raw);
|
|
31
|
-
}
|
|
32
|
-
function loadSubAgentsConfig() {
|
|
33
|
-
if (configCache)
|
|
34
|
-
return configCache;
|
|
35
|
-
try {
|
|
36
|
-
const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
37
|
-
const parsed = JSON.parse(raw);
|
|
38
|
-
configCache = {
|
|
39
|
-
maxParallel: typeof parsed.maxParallel === "number" ? parsed.maxParallel : 0,
|
|
40
|
-
visibility: isValidVisibility(parsed.visibility) ? parsed.visibility : "auto",
|
|
41
|
-
queueCap: typeof parsed.queueCap === "number"
|
|
42
|
-
? Math.max(0, Math.min(Math.floor(parsed.queueCap), ABSOLUTE_MAX_QUEUE))
|
|
43
|
-
: DEFAULT_QUEUE_CAP,
|
|
44
|
-
defaultTimeoutMs: typeof parsed.defaultTimeoutMs === "number" && Number.isFinite(parsed.defaultTimeoutMs)
|
|
45
|
-
? (parsed.defaultTimeoutMs <= 0 ? -1 : Math.floor(parsed.defaultTimeoutMs))
|
|
46
|
-
: seedDefaultTimeout(),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
// File missing or invalid — seed from env vars then default to auto/unlimited
|
|
51
|
-
configCache = {
|
|
52
|
-
maxParallel: Number(process.env.MAX_SUBAGENTS) || 0,
|
|
53
|
-
visibility: "auto",
|
|
54
|
-
queueCap: DEFAULT_QUEUE_CAP,
|
|
55
|
-
defaultTimeoutMs: seedDefaultTimeout(),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
return configCache;
|
|
59
|
-
}
|
|
60
|
-
function saveSubAgentsConfig(cfg) {
|
|
61
|
-
try {
|
|
62
|
-
fs.mkdirSync(dirname(CONFIG_FILE), { recursive: true });
|
|
63
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), "utf-8");
|
|
64
|
-
configCache = cfg;
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
console.error("[subagents] failed to write config:", err);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/** Resolves max parallel agents, interpreting 0 as "auto = cpu cores capped". */
|
|
71
|
-
export function getMaxParallelAgents() {
|
|
72
|
-
const cfg = loadSubAgentsConfig();
|
|
73
|
-
if (cfg.maxParallel === 0) {
|
|
74
|
-
return Math.min(os.cpus().length, ABSOLUTE_MAX_AGENTS);
|
|
75
|
-
}
|
|
76
|
-
return Math.min(Math.max(1, cfg.maxParallel), ABSOLUTE_MAX_AGENTS);
|
|
77
|
-
}
|
|
78
|
-
/** Returns the raw configured value (for display). 0 means "auto". */
|
|
79
|
-
export function getConfiguredMaxParallel() {
|
|
80
|
-
return loadSubAgentsConfig().maxParallel;
|
|
81
|
-
}
|
|
82
|
-
/** Sets max parallel agents. Value is clamped to [0, ABSOLUTE_MAX_AGENTS].
|
|
83
|
-
* Returns the resolved effective value (with auto-expansion if set to 0). */
|
|
84
|
-
export function setMaxParallelAgents(n) {
|
|
85
|
-
const clamped = Math.max(0, Math.min(Math.floor(n), ABSOLUTE_MAX_AGENTS));
|
|
86
|
-
const cfg = loadSubAgentsConfig();
|
|
87
|
-
saveSubAgentsConfig({ ...cfg, maxParallel: clamped });
|
|
88
|
-
return getMaxParallelAgents();
|
|
89
|
-
}
|
|
90
|
-
/** A4: Current default visibility mode for new spawns. */
|
|
91
|
-
export function getVisibility() {
|
|
92
|
-
return loadSubAgentsConfig().visibility;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* A4: Set the default visibility mode. Throws if the value is invalid.
|
|
96
|
-
* Writes through to the on-disk config so restart-resilient.
|
|
97
|
-
*/
|
|
98
|
-
export function setVisibility(mode) {
|
|
99
|
-
if (!isValidVisibility(mode)) {
|
|
100
|
-
throw new Error(`Invalid visibility mode "${mode}". Expected: auto | banner | silent | live.`);
|
|
101
|
-
}
|
|
102
|
-
const cfg = loadSubAgentsConfig();
|
|
103
|
-
saveSubAgentsConfig({ ...cfg, visibility: mode });
|
|
104
|
-
}
|
|
105
|
-
/** D3: Current bounded-queue cap. 0 = queue disabled (reject on full pool). */
|
|
106
|
-
export function getQueueCap() {
|
|
107
|
-
return loadSubAgentsConfig().queueCap;
|
|
108
|
-
}
|
|
109
|
-
/** D3: Set the queue cap. Clamped to [0, ABSOLUTE_MAX_QUEUE].
|
|
110
|
-
* Returns the effective value after clamping. */
|
|
111
|
-
export function setQueueCap(n) {
|
|
112
|
-
const clamped = Math.max(0, Math.min(Math.floor(n), ABSOLUTE_MAX_QUEUE));
|
|
113
|
-
const cfg = loadSubAgentsConfig();
|
|
114
|
-
saveSubAgentsConfig({ ...cfg, queueCap: clamped });
|
|
115
|
-
return clamped;
|
|
116
|
-
}
|
|
117
|
-
/** Current default timeout in ms. -1 = unlimited. */
|
|
118
|
-
export function getDefaultTimeoutMs() {
|
|
119
|
-
return loadSubAgentsConfig().defaultTimeoutMs;
|
|
120
|
-
}
|
|
121
|
-
/** Set the default timeout in ms. Any value ≤ 0 or non-finite collapses
|
|
122
|
-
* to -1 (unlimited). Returns the persisted value. */
|
|
123
|
-
export function setDefaultTimeoutMs(ms) {
|
|
124
|
-
const normalized = !Number.isFinite(ms) || ms <= 0 ? -1 : Math.floor(ms);
|
|
125
|
-
const cfg = loadSubAgentsConfig();
|
|
126
|
-
saveSubAgentsConfig({ ...cfg, defaultTimeoutMs: normalized });
|
|
127
|
-
return normalized;
|
|
128
|
-
}
|
|
129
|
-
// ── State ───────────────────────────────────────────────
|
|
130
|
-
const activeAgents = new Map();
|
|
131
|
-
/**
|
|
132
|
-
* Hard cap on the activeAgents map. Without this, a long-running bot that
|
|
133
|
-
* spawns many agents (e.g. a chatty cron + manual triggers over months) would
|
|
134
|
-
* accumulate delivered entries indefinitely. The 30-min auto-cleanup inside
|
|
135
|
-
* runSubAgent only fires on graceful completion, so crashed/orphaned entries
|
|
136
|
-
* would linger until the 12h giveUpAt ceiling.
|
|
137
|
-
*
|
|
138
|
-
* Enforcement: whenever we insert a new entry and the map is at-or-over the
|
|
139
|
-
* cap, evict the oldest finished-and-delivered entries first. Running agents
|
|
140
|
-
* are never evicted.
|
|
141
|
-
*/
|
|
142
|
-
const MAX_ACTIVE_AGENTS = 1000;
|
|
143
|
-
function enforceAgentCap() {
|
|
144
|
-
if (activeAgents.size < MAX_ACTIVE_AGENTS)
|
|
145
|
-
return;
|
|
146
|
-
// Collect evictable entries (delivered OR terminal status), sort by startedAt
|
|
147
|
-
const evictable = [];
|
|
148
|
-
for (const [id, entry] of activeAgents) {
|
|
149
|
-
const status = entry.info.status;
|
|
150
|
-
const done = entry.delivered || status === "error" || status === "timeout" || status === "cancelled";
|
|
151
|
-
if (done)
|
|
152
|
-
evictable.push([id, entry.info.startedAt]);
|
|
153
|
-
}
|
|
154
|
-
evictable.sort((a, b) => a[1] - b[1]);
|
|
155
|
-
// Evict enough to land 10% below the cap, so we don't oscillate.
|
|
156
|
-
const target = Math.floor(MAX_ACTIVE_AGENTS * 0.9);
|
|
157
|
-
let toEvict = activeAgents.size - target;
|
|
158
|
-
for (const [id] of evictable) {
|
|
159
|
-
if (toEvict <= 0)
|
|
160
|
-
break;
|
|
161
|
-
activeAgents.delete(id);
|
|
162
|
-
toEvict--;
|
|
163
|
-
}
|
|
164
|
-
if (toEvict > 0) {
|
|
165
|
-
console.warn(`[subagents] map at ${activeAgents.size}/${MAX_ACTIVE_AGENTS} — could not evict enough finished entries (too many still running)`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
// ── Name resolver (B2) ──────────────────────────────────
|
|
169
|
-
/**
|
|
170
|
-
* Return all currently-tracked agents whose *base* name matches `base`.
|
|
171
|
-
* Base name = the part before any "#N" suffix.
|
|
172
|
-
*/
|
|
173
|
-
function agentsByBaseName(base) {
|
|
174
|
-
const out = [];
|
|
175
|
-
for (const entry of activeAgents.values()) {
|
|
176
|
-
const info = entry.info;
|
|
177
|
-
const entryBase = info.name.replace(/#\d+$/, "");
|
|
178
|
-
if (entryBase === base)
|
|
179
|
-
out.push(info);
|
|
180
|
-
}
|
|
181
|
-
return out;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Given a requested name, return a unique variant. If no collision exists,
|
|
185
|
-
* returns `requested` unchanged (with the base form). Otherwise returns
|
|
186
|
-
* `base#N` with the smallest free N ≥ 2.
|
|
187
|
-
*/
|
|
188
|
-
function resolveAgentName(requested) {
|
|
189
|
-
const base = requested.replace(/#\d+$/, "");
|
|
190
|
-
const siblings = agentsByBaseName(base);
|
|
191
|
-
if (siblings.length === 0)
|
|
192
|
-
return { name: base };
|
|
193
|
-
// Find the smallest free index ≥ 2. The bare base name counts as "#1".
|
|
194
|
-
const takenIndices = new Set();
|
|
195
|
-
for (const s of siblings) {
|
|
196
|
-
const m = s.name.match(/#(\d+)$/);
|
|
197
|
-
if (m)
|
|
198
|
-
takenIndices.add(parseInt(m[1], 10));
|
|
199
|
-
else
|
|
200
|
-
takenIndices.add(1);
|
|
201
|
-
}
|
|
202
|
-
let n = 2;
|
|
203
|
-
while (takenIndices.has(n))
|
|
204
|
-
n++;
|
|
205
|
-
return { name: `${base}#${n}`, index: n };
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Public name-resolution API used by /sub-agents cancel / result.
|
|
209
|
-
* - Exact name match wins (e.g. "review#2" finds exactly that entry).
|
|
210
|
-
* - If only one agent matches the base name, returns that one.
|
|
211
|
-
* - If the caller opted into `ambiguousAsList`, returns a disambiguation
|
|
212
|
-
* marker with all candidates instead of a single result.
|
|
213
|
-
*/
|
|
214
|
-
export function findSubAgentByName(name, opts = {}) {
|
|
215
|
-
// An explicit "base#N" query must always resolve to that exact entry,
|
|
216
|
-
// even when the caller opted into ambiguity. Otherwise users who type
|
|
217
|
-
// out the disambiguated form get an unhelpful 'which one?' reply.
|
|
218
|
-
const hasExplicitSuffix = /#\d+$/.test(name);
|
|
219
|
-
if (hasExplicitSuffix) {
|
|
220
|
-
for (const entry of activeAgents.values()) {
|
|
221
|
-
if (entry.info.name === name)
|
|
222
|
-
return { ...entry.info };
|
|
223
|
-
}
|
|
224
|
-
return null;
|
|
225
|
-
}
|
|
226
|
-
// No explicit suffix → base-name query. Ambiguity detection runs here
|
|
227
|
-
// when the caller opted in and there are multiple siblings.
|
|
228
|
-
const siblings = agentsByBaseName(name);
|
|
229
|
-
if (siblings.length === 0)
|
|
230
|
-
return null;
|
|
231
|
-
if (opts.ambiguousAsList && siblings.length > 1) {
|
|
232
|
-
return {
|
|
233
|
-
ambiguous: true,
|
|
234
|
-
candidates: siblings.map((s) => ({ ...s })),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
// Without ambiguity opt-in, prefer an exact name match over just the
|
|
238
|
-
// first sibling — the bare base name is itself a unique key.
|
|
239
|
-
for (const entry of activeAgents.values()) {
|
|
240
|
-
if (entry.info.name === name)
|
|
241
|
-
return { ...entry.info };
|
|
242
|
-
}
|
|
243
|
-
return { ...siblings[0] };
|
|
244
|
-
}
|
|
245
|
-
// ── Core execution ──────────────────────────────────────
|
|
246
|
-
async function runSubAgent(id, agentConfig, abort, resolvedName) {
|
|
247
|
-
const startTime = Date.now();
|
|
248
|
-
const entry = activeAgents.get(id);
|
|
249
|
-
// A4 live-stream state — set up if the effective visibility is "live"
|
|
250
|
-
// AND this is a user spawn with a parent chat. Cron and implicit spawns
|
|
251
|
-
// don't get live-streaming (cron because there's no interactive watcher,
|
|
252
|
-
// implicit because the parent Claude stream already shows everything).
|
|
253
|
-
let liveStream = null;
|
|
254
|
-
const effectiveVisibility = agentConfig.visibility ?? loadSubAgentsConfig().visibility;
|
|
255
|
-
if (effectiveVisibility === "live" &&
|
|
256
|
-
agentConfig.source === "user" &&
|
|
257
|
-
typeof agentConfig.parentChatId === "number") {
|
|
258
|
-
try {
|
|
259
|
-
const { createLiveStream } = await import("./subagent-delivery.js");
|
|
260
|
-
const stream = createLiveStream(agentConfig.parentChatId, resolvedName);
|
|
261
|
-
if (stream) {
|
|
262
|
-
await stream.start();
|
|
263
|
-
if (!stream.failed)
|
|
264
|
-
liveStream = stream;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
catch (err) {
|
|
268
|
-
console.error(`[subagent ${id}] live-stream init failed:`, err);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
// These live OUTSIDE the try block so the catch handler can read
|
|
272
|
-
// whatever was buffered before the stream failed. Moving them into
|
|
273
|
-
// the try scope was the cause of the "output: ''" regression.
|
|
274
|
-
let finalText = "";
|
|
275
|
-
let inputTokens = 0;
|
|
276
|
-
let outputTokens = 0;
|
|
277
|
-
let streamError = null;
|
|
278
|
-
try {
|
|
279
|
-
const { getRegistry } = await import("../engine.js");
|
|
280
|
-
const registry = getRegistry();
|
|
281
|
-
// C3: inheritCwd (default true) decides whether the parent's working
|
|
282
|
-
// dir flows through. When false, we fall back to the home directory —
|
|
283
|
-
// useful for cron jobs that must run in a well-known root regardless
|
|
284
|
-
// of what the caller was doing.
|
|
285
|
-
const inheritCwd = agentConfig.inheritCwd ?? true;
|
|
286
|
-
const effectiveCwd = inheritCwd
|
|
287
|
-
? agentConfig.workingDir || os.homedir()
|
|
288
|
-
: os.homedir();
|
|
289
|
-
const systemPrompt = `You are a sub-agent named "${resolvedName}". Complete the following task autonomously. Working directory: ${effectiveCwd}
|
|
290
|
-
|
|
291
|
-
Do NOT send your own Telegram/chat/notification messages as a step, and do NOT use any tool or skill to message the user or post your progress — your final return value is the SOLE delivery path and the orchestrator delivers it for you. A self-sent message causes a duplicate the user sees twice.
|
|
292
|
-
|
|
293
|
-
When done, return ONLY the final result/outcome itself, concisely — nothing else. Do NOT narrate, summarize, or recap your intermediate steps, your reasoning, your tool calls, your plan, or a play-by-play of what you did. The orchestrator needs ONLY the outcome (the answer, the report, the list, the artifact path); on failure, return the error plus exactly what was and wasn't done. No preamble, no meta-commentary, no "Here's what I did", no "I will now…", no step-by-step recap. Run status, duration and token usage are reported separately, so don't restate them.`;
|
|
294
|
-
// v4.12.2 — Map the toolset preset to an explicit allowedTools list.
|
|
295
|
-
// The provider honors this override (see src/providers/claude-sdk-provider.ts
|
|
296
|
-
// line ~140). Passing undefined = full access (provider default).
|
|
297
|
-
const allowedToolsForToolset = (preset) => {
|
|
298
|
-
switch (preset) {
|
|
299
|
-
case "readonly":
|
|
300
|
-
// Read, analyze, search — no writes, no shell, no network.
|
|
301
|
-
return ["Read", "Glob", "Grep"];
|
|
302
|
-
case "research":
|
|
303
|
-
// Same as readonly + web access for research tasks.
|
|
304
|
-
return ["Read", "Glob", "Grep", "WebSearch", "WebFetch"];
|
|
305
|
-
case "full":
|
|
306
|
-
default:
|
|
307
|
-
// undefined → provider uses its full default set.
|
|
308
|
-
return undefined;
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
for await (const chunk of registry.queryWithFallback({
|
|
312
|
-
prompt: agentConfig.prompt,
|
|
313
|
-
systemPrompt,
|
|
314
|
-
workingDir: effectiveCwd,
|
|
315
|
-
effort: "high",
|
|
316
|
-
abortSignal: abort.signal,
|
|
317
|
-
allowedTools: allowedToolsForToolset(agentConfig.toolset ?? "full"),
|
|
318
|
-
})) {
|
|
319
|
-
if (chunk.type === "text") {
|
|
320
|
-
// Both SDK providers emit `text` as the accumulated string.
|
|
321
|
-
// Keep the last non-empty one we've seen so a final tool-only
|
|
322
|
-
// turn doesn't wipe our buffer.
|
|
323
|
-
if (chunk.text && chunk.text.length > 0) {
|
|
324
|
-
finalText = chunk.text;
|
|
325
|
-
}
|
|
326
|
-
if (liveStream && !liveStream.failed) {
|
|
327
|
-
liveStream.update(finalText);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
if (chunk.type === "done") {
|
|
331
|
-
// V56-T1 — Prefer the SDK's authoritative FINAL result over the
|
|
332
|
-
// accumulated narration. The Claude Agent SDK emits a terminal
|
|
333
|
-
// `result` message whose single `result` field IS the agent's
|
|
334
|
-
// actual outcome; the provider surfaces it as `chunk.finalResult`.
|
|
335
|
-
// Using it here excludes the step-by-step narration BY
|
|
336
|
-
// CONSTRUCTION (it's a distinct SDK field, not a heuristic over
|
|
337
|
-
// concatenated text), matching what the detached-dispatch path
|
|
338
|
-
// already does. When the provider has no distinct final-result
|
|
339
|
-
// message (non-SDK providers, SDK error results), finalResult is
|
|
340
|
-
// undefined and we fall back to done.text — the previous
|
|
341
|
-
// authoritative-accumulated-text behaviour, so streamed-text
|
|
342
|
-
// consumers and the Fix #5 contract are unaffected.
|
|
343
|
-
if (typeof chunk.finalResult === "string" && chunk.finalResult.length > 0) {
|
|
344
|
-
finalText = chunk.finalResult;
|
|
345
|
-
}
|
|
346
|
-
else if (chunk.text && chunk.text.length > 0) {
|
|
347
|
-
finalText = chunk.text;
|
|
348
|
-
}
|
|
349
|
-
inputTokens = chunk.inputTokens || 0;
|
|
350
|
-
outputTokens = chunk.outputTokens || 0;
|
|
351
|
-
}
|
|
352
|
-
if (chunk.type === "error") {
|
|
353
|
-
// Providers surface mid-stream errors as an `error` chunk
|
|
354
|
-
// instead of throwing. Capture the reason so the post-loop
|
|
355
|
-
// status resolution below can distinguish this from a clean
|
|
356
|
-
// finish, and keep whatever text we already buffered.
|
|
357
|
-
streamError = chunk.error || "stream error";
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
// If cancelAllSubAgents has already taken over (shutdown path), don't
|
|
361
|
-
// overwrite the cancelled result it synthesised. Also: if the generator
|
|
362
|
-
// exited gracefully but the abort signal fired mid-stream (e.g. the
|
|
363
|
-
// provider's queryWithFallback returned `type:error` and we fell out
|
|
364
|
-
// of the loop without throwing), mark the run as cancelled rather
|
|
365
|
-
// than completed — the result output is whatever we buffered.
|
|
366
|
-
if (entry.result && entry.result.status === "cancelled") {
|
|
367
|
-
// cancelAllSubAgents already set this; nothing to do.
|
|
368
|
-
}
|
|
369
|
-
else if (abort.signal.aborted) {
|
|
370
|
-
entry.result = {
|
|
371
|
-
id,
|
|
372
|
-
name: resolvedName,
|
|
373
|
-
status: "cancelled",
|
|
374
|
-
output: finalText,
|
|
375
|
-
tokensUsed: { input: inputTokens, output: outputTokens },
|
|
376
|
-
duration: Date.now() - startTime,
|
|
377
|
-
};
|
|
378
|
-
entry.info.status = "cancelled";
|
|
379
|
-
}
|
|
380
|
-
else if (streamError) {
|
|
381
|
-
// Provider emitted an error chunk but the generator ended cleanly —
|
|
382
|
-
// record it as an error, but preserve the text buffered before the
|
|
383
|
-
// failure so the caller sees useful partial output instead of "".
|
|
384
|
-
entry.result = {
|
|
385
|
-
id,
|
|
386
|
-
name: resolvedName,
|
|
387
|
-
status: "error",
|
|
388
|
-
output: finalText,
|
|
389
|
-
tokensUsed: { input: inputTokens, output: outputTokens },
|
|
390
|
-
duration: Date.now() - startTime,
|
|
391
|
-
error: streamError,
|
|
392
|
-
};
|
|
393
|
-
entry.info.status = "error";
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
entry.result = {
|
|
397
|
-
id,
|
|
398
|
-
name: resolvedName,
|
|
399
|
-
status: "completed",
|
|
400
|
-
output: finalText,
|
|
401
|
-
tokensUsed: { input: inputTokens, output: outputTokens },
|
|
402
|
-
duration: Date.now() - startTime,
|
|
403
|
-
};
|
|
404
|
-
entry.info.status = "completed";
|
|
405
|
-
}
|
|
406
|
-
// A4: finalize the live-stream if we had one. On success, mark the
|
|
407
|
-
// entry as delivered so spawnSubAgent.finally() skips the normal
|
|
408
|
-
// deliverSubAgentResult path — the live stream already posted the
|
|
409
|
-
// body, and finalize() already posted the banner.
|
|
410
|
-
if (liveStream && !liveStream.failed && entry.result) {
|
|
411
|
-
try {
|
|
412
|
-
await liveStream.finalize(entry.info, entry.result);
|
|
413
|
-
entry.delivered = true;
|
|
414
|
-
}
|
|
415
|
-
catch (err) {
|
|
416
|
-
console.error(`[subagent ${id}] live-stream finalize failed:`, err);
|
|
417
|
-
// Let the normal delivery path fire as a fallback.
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
catch (err) {
|
|
422
|
-
// If cancelAllSubAgents already set a cancelled result, keep it.
|
|
423
|
-
if (entry.result && entry.result.status === "cancelled")
|
|
424
|
-
return;
|
|
425
|
-
const isAbort = err instanceof Error && err.message.includes("abort");
|
|
426
|
-
const isTimeout = abort.signal.aborted;
|
|
427
|
-
const status = isTimeout
|
|
428
|
-
? "timeout"
|
|
429
|
-
: isAbort
|
|
430
|
-
? "cancelled"
|
|
431
|
-
: "error";
|
|
432
|
-
entry.result = {
|
|
433
|
-
id,
|
|
434
|
-
name: resolvedName,
|
|
435
|
-
// Preserve whatever text was buffered before the failure.
|
|
436
|
-
// Empty output here used to throw away multi-minute runs.
|
|
437
|
-
output: finalText,
|
|
438
|
-
tokensUsed: { input: inputTokens, output: outputTokens },
|
|
439
|
-
duration: Date.now() - startTime,
|
|
440
|
-
error: err instanceof Error ? err.message : String(err),
|
|
441
|
-
status,
|
|
442
|
-
};
|
|
443
|
-
entry.info.status = status;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
const pendingQueue = [];
|
|
447
|
-
/** Priority order used when draining the queue — higher index = lower priority. */
|
|
448
|
-
const SOURCE_PRIORITY = ["user", "cron", "implicit"];
|
|
449
|
-
function sourceOf(cfg) {
|
|
450
|
-
return cfg.source ?? "implicit";
|
|
451
|
-
}
|
|
452
|
-
/** Count how many agents are currently running. */
|
|
453
|
-
function runningCount() {
|
|
454
|
-
return [...activeAgents.values()].filter((a) => a.info.status === "running").length;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Pop the next queued spawn according to priority (user > cron > implicit)
|
|
458
|
-
* and within each priority in FIFO order. Returns null if the queue is empty.
|
|
459
|
-
*/
|
|
460
|
-
function popHighestPriorityQueued() {
|
|
461
|
-
for (const priority of SOURCE_PRIORITY) {
|
|
462
|
-
const idx = pendingQueue.findIndex((q) => sourceOf(q.agentConfig) === priority);
|
|
463
|
-
if (idx >= 0) {
|
|
464
|
-
const [entry] = pendingQueue.splice(idx, 1);
|
|
465
|
-
return entry;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Recalculate queuePosition for every entry still in the queue. Called
|
|
472
|
-
* after a pop or a cancel so /subagents list reflects the current state.
|
|
473
|
-
*/
|
|
474
|
-
function reindexQueue() {
|
|
475
|
-
for (let i = 0; i < pendingQueue.length; i++) {
|
|
476
|
-
const q = pendingQueue[i];
|
|
477
|
-
const entry = activeAgents.get(q.id);
|
|
478
|
-
if (entry)
|
|
479
|
-
entry.info.queuePosition = i + 1;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
/** Drain as many queued spawns as fit into the current free slots. */
|
|
483
|
-
function drainQueue() {
|
|
484
|
-
const maxParallel = getMaxParallelAgents();
|
|
485
|
-
while (pendingQueue.length > 0 && runningCount() < maxParallel) {
|
|
486
|
-
const next = popHighestPriorityQueued();
|
|
487
|
-
if (!next)
|
|
488
|
-
break;
|
|
489
|
-
const entry = activeAgents.get(next.id);
|
|
490
|
-
if (!entry)
|
|
491
|
-
continue; // was cancelled while queued
|
|
492
|
-
reindexQueue();
|
|
493
|
-
// Transition to running
|
|
494
|
-
entry.info.status = "running";
|
|
495
|
-
entry.info.startedAt = Date.now();
|
|
496
|
-
entry.info.queuePosition = undefined;
|
|
497
|
-
startRun(next);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
// ── Spawn pipeline ──────────────────────────────────────────
|
|
501
|
-
function startRun(q) {
|
|
502
|
-
const { id, resolvedName, agentConfig, timeoutId } = q;
|
|
503
|
-
const entry = activeAgents.get(id);
|
|
504
|
-
if (!entry)
|
|
505
|
-
return;
|
|
506
|
-
// Run in background — don't await
|
|
507
|
-
runSubAgent(id, agentConfig, entry.abort, resolvedName)
|
|
508
|
-
.finally(() => {
|
|
509
|
-
if (timeoutId)
|
|
510
|
-
clearTimeout(timeoutId);
|
|
511
|
-
const currentEntry = activeAgents.get(id);
|
|
512
|
-
if (agentConfig.onComplete && currentEntry?.result) {
|
|
513
|
-
try {
|
|
514
|
-
agentConfig.onComplete(currentEntry.result);
|
|
515
|
-
}
|
|
516
|
-
catch (err) {
|
|
517
|
-
console.error(`[subagent ${id}] onComplete callback threw:`, err);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// I3: fire delivery router (non-blocking, errors logged). Guarded
|
|
521
|
-
// by the `delivered` flag.
|
|
522
|
-
if (currentEntry?.result && !currentEntry.delivered) {
|
|
523
|
-
currentEntry.delivered = true;
|
|
524
|
-
const resultSnapshot = currentEntry.result;
|
|
525
|
-
const infoSnapshot = currentEntry.info;
|
|
526
|
-
import("./subagent-delivery.js")
|
|
527
|
-
.then(({ deliverSubAgentResult }) => deliverSubAgentResult(infoSnapshot, resultSnapshot, {
|
|
528
|
-
visibility: agentConfig.visibility,
|
|
529
|
-
}))
|
|
530
|
-
.catch((err) => console.error(`[subagent ${id}] delivery failed:`, err));
|
|
531
|
-
}
|
|
532
|
-
// H3: record this run in the rolling 24h stats (non-blocking).
|
|
533
|
-
if (currentEntry?.result) {
|
|
534
|
-
const resultSnapshot = currentEntry.result;
|
|
535
|
-
const infoSnapshot = currentEntry.info;
|
|
536
|
-
import("./subagent-stats.js")
|
|
537
|
-
.then(({ recordSubAgentRun }) => recordSubAgentRun(infoSnapshot, resultSnapshot))
|
|
538
|
-
.catch((err) => console.error(`[subagent ${id}] stats recording failed:`, err));
|
|
539
|
-
}
|
|
540
|
-
// D3: drain the queue now that a slot has freed up
|
|
541
|
-
drainQueue();
|
|
542
|
-
// Auto-cleanup: remove completed agents after 30 minutes
|
|
543
|
-
setTimeout(() => {
|
|
544
|
-
const e = activeAgents.get(id);
|
|
545
|
-
if (e && e.info.status !== "running" && e.info.status !== "queued") {
|
|
546
|
-
activeAgents.delete(id);
|
|
547
|
-
}
|
|
548
|
-
}, 30 * 60 * 1000);
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
export function spawnSubAgent(agentConfig) {
|
|
552
|
-
// F2: enforce depth cap before touching any state.
|
|
553
|
-
const depth = agentConfig.depth ?? 0;
|
|
554
|
-
if (depth > MAX_SUBAGENT_DEPTH) {
|
|
555
|
-
return Promise.reject(new Error(`Sub-agent depth limit reached (${MAX_SUBAGENT_DEPTH}). Agents can only spawn ${MAX_SUBAGENT_DEPTH} level(s) of nested agents.`));
|
|
556
|
-
}
|
|
557
|
-
// G1: toolset preset (v4.12.2 — extended with readonly + research).
|
|
558
|
-
// The literal type constrains at compile time; the runtime check catches
|
|
559
|
-
// callers that bypass TypeScript (e.g. plugin code loaded at runtime).
|
|
560
|
-
const toolset = agentConfig.toolset ?? "full";
|
|
561
|
-
if (toolset !== "full" && toolset !== "readonly" && toolset !== "research") {
|
|
562
|
-
return Promise.reject(new Error(`Invalid toolset "${toolset}". Valid presets: full, readonly, research.`));
|
|
563
|
-
}
|
|
564
|
-
const maxParallel = getMaxParallelAgents();
|
|
565
|
-
const queueCap = getQueueCap();
|
|
566
|
-
const running = runningCount();
|
|
567
|
-
const queuedLen = pendingQueue.length;
|
|
568
|
-
// B2: resolve the requested name to a unique variant.
|
|
569
|
-
const resolved = resolveAgentName(agentConfig.name);
|
|
570
|
-
const resolvedName = resolved.name;
|
|
571
|
-
const id = crypto.randomUUID();
|
|
572
|
-
// Timeout resolution order:
|
|
573
|
-
// 1. Per-spawn override (agentConfig.timeout) — used by cron jobs that
|
|
574
|
-
// carry their own timeoutMs.
|
|
575
|
-
// 2. Runtime default from sub-agents.json (set via /subagents timeout).
|
|
576
|
-
// 3. config.subAgentTimeout fallback (seeded from SUBAGENT_TIMEOUT env).
|
|
577
|
-
// Any value ≤ 0 means "no timeout" — we simply don't arm the abort timer.
|
|
578
|
-
// The existing null-safe `clearTimeout(timeoutId)` call sites make this
|
|
579
|
-
// a safe no-op when the agent finishes or is cancelled.
|
|
580
|
-
const timeout = agentConfig.timeout ?? getDefaultTimeoutMs();
|
|
581
|
-
const abort = new AbortController();
|
|
582
|
-
const timeoutId = timeout > 0 ? setTimeout(() => abort.abort(), timeout) : null;
|
|
583
|
-
const willRunImmediately = running < maxParallel;
|
|
584
|
-
const canQueue = !willRunImmediately && queueCap > 0 && queuedLen < queueCap;
|
|
585
|
-
if (!willRunImmediately && !canQueue) {
|
|
586
|
-
// No slot, no queue room → priority-aware reject
|
|
587
|
-
if (timeoutId)
|
|
588
|
-
clearTimeout(timeoutId);
|
|
589
|
-
const source = sourceOf(agentConfig);
|
|
590
|
-
const runningAgents = [...activeAgents.values()].filter((a) => a.info.status === "running");
|
|
591
|
-
const userSlots = runningAgents.filter((a) => a.info.source === "user").length;
|
|
592
|
-
const bgSlots = runningAgents.length - userSlots;
|
|
593
|
-
let message;
|
|
594
|
-
if (source === "user") {
|
|
595
|
-
if (bgSlots > 0) {
|
|
596
|
-
message = `Alle Slots belegt (${running}/${maxParallel}), davon ${bgSlots} cron/implicit im Hintergrund. Queue voll (${queuedLen}/${queueCap}). /subagents list für Details oder /subagents cancel <name>.`;
|
|
597
|
-
}
|
|
598
|
-
else {
|
|
599
|
-
message = `Alle Slots belegt (${running}/${maxParallel}) mit eigenen user-Spawns. Queue voll (${queuedLen}/${queueCap}). /subagents cancel <name> oder warten.`;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
message = `Sub-agent limit reached (${maxParallel} running, ${queuedLen}/${queueCap} queued). Wait for a running agent to finish or cancel one.`;
|
|
604
|
-
}
|
|
605
|
-
return Promise.reject(new Error(message));
|
|
606
|
-
}
|
|
607
|
-
const info = {
|
|
608
|
-
id,
|
|
609
|
-
name: resolvedName,
|
|
610
|
-
status: willRunImmediately ? "running" : "queued",
|
|
611
|
-
startedAt: Date.now(),
|
|
612
|
-
model: agentConfig.model,
|
|
613
|
-
source: agentConfig.source,
|
|
614
|
-
depth,
|
|
615
|
-
parentChatId: agentConfig.parentChatId,
|
|
616
|
-
nameIndex: resolved.index,
|
|
617
|
-
queuePosition: willRunImmediately ? undefined : queuedLen + 1,
|
|
618
|
-
};
|
|
619
|
-
enforceAgentCap();
|
|
620
|
-
activeAgents.set(id, { info, abort, delivered: false });
|
|
621
|
-
const queuedSpawn = { id, resolvedName, agentConfig, depth, timeoutId };
|
|
622
|
-
if (willRunImmediately) {
|
|
623
|
-
startRun(queuedSpawn);
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
pendingQueue.push(queuedSpawn);
|
|
627
|
-
reindexQueue();
|
|
628
|
-
}
|
|
629
|
-
return Promise.resolve(id);
|
|
630
|
-
}
|
|
631
|
-
/**
|
|
632
|
-
* List all agents (active + recent completed).
|
|
633
|
-
*
|
|
634
|
-
* This is the v4.0.0 API — shows only agents from the bot-level
|
|
635
|
-
* registry (activeAgents Map). Does NOT include v4.13+ detached
|
|
636
|
-
* `alvin_dispatch_agent` subprocesses which live in async-agent-
|
|
637
|
-
* watcher. For the merged view used by `/subagents list`, use
|
|
638
|
-
* `listActiveSubAgents()` instead.
|
|
639
|
-
*/
|
|
640
|
-
export function listSubAgents() {
|
|
641
|
-
return [...activeAgents.values()].map((a) => ({ ...a.info }));
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* v4.14.1 — Merged view of BOTH sub-agent registries:
|
|
645
|
-
* 1. Bot-level agents (subagents.ts activeAgents Map) — v4.0.0+
|
|
646
|
-
* the /sub-agents spawn CLI, cron-spawned sub-agents, implicit
|
|
647
|
-
* Task-tool children.
|
|
648
|
-
* 2. Detached `alvin_dispatch_agent` subprocesses (async-agent-
|
|
649
|
-
* watcher pending Map) — v4.13+ the MCP-tool-dispatched
|
|
650
|
-
* agents that survive parent aborts.
|
|
651
|
-
*
|
|
652
|
-
* The user doesn't care which registry an agent lives in — "is there
|
|
653
|
-
* anything running right now?" is the question `/subagents list`
|
|
654
|
-
* answers. This function unifies the view.
|
|
655
|
-
*
|
|
656
|
-
* Pending async agents are synthesized into SubAgentInfo shape:
|
|
657
|
-
* - id: PendingAsyncAgent.agentId (alvin-prefixed hex)
|
|
658
|
-
* - name: PendingAsyncAgent.description
|
|
659
|
-
* - status: "running" (we wouldn't be pending otherwise)
|
|
660
|
-
* - startedAt: PendingAsyncAgent.startedAt
|
|
661
|
-
* - source: "cron" — matches the delivery banner's source tag
|
|
662
|
-
* - depth: 0 — dispatch agents are always top-level (no nesting)
|
|
663
|
-
* - platform: preserved from the pending entry
|
|
664
|
-
* - parentChatId: from the pending entry
|
|
665
|
-
*
|
|
666
|
-
* Lazy import of the watcher keeps this function cheap for callers
|
|
667
|
-
* who only need the v4.0.0 view (importing the watcher pulls in its
|
|
668
|
-
* whole startup cost otherwise).
|
|
669
|
-
*/
|
|
670
|
-
export async function listActiveSubAgents() {
|
|
671
|
-
const botLevel = listSubAgents();
|
|
672
|
-
let pending = [];
|
|
673
|
-
try {
|
|
674
|
-
// Lazy dynamic import so this module doesn't depend on the watcher
|
|
675
|
-
// at load time (preserves test isolation + avoids a circular boot).
|
|
676
|
-
const watcher = await import("./async-agent-watcher.js");
|
|
677
|
-
if (typeof watcher.listPendingAgents === "function") {
|
|
678
|
-
const raw = watcher.listPendingAgents();
|
|
679
|
-
pending = raw.map((p) => ({
|
|
680
|
-
id: p.agentId,
|
|
681
|
-
name: p.description,
|
|
682
|
-
status: "running",
|
|
683
|
-
startedAt: p.startedAt,
|
|
684
|
-
source: "cron",
|
|
685
|
-
depth: 0,
|
|
686
|
-
platform: p.platform,
|
|
687
|
-
parentChatId: p.chatId,
|
|
688
|
-
}));
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
catch {
|
|
692
|
-
/* never break listing because of merge errors */
|
|
693
|
-
}
|
|
694
|
-
return [...botLevel, ...pending];
|
|
695
|
-
}
|
|
696
|
-
/**
|
|
697
|
-
* Cancel a running sub-agent by ID.
|
|
698
|
-
* Returns true if the agent was found and aborted.
|
|
699
|
-
*/
|
|
700
|
-
export function cancelSubAgent(id) {
|
|
701
|
-
const entry = activeAgents.get(id);
|
|
702
|
-
if (!entry)
|
|
703
|
-
return false;
|
|
704
|
-
if (entry.info.status === "queued") {
|
|
705
|
-
// D3: remove from the pending queue, reindex, mark cancelled.
|
|
706
|
-
const idx = pendingQueue.findIndex((q) => q.id === id);
|
|
707
|
-
if (idx >= 0) {
|
|
708
|
-
const [removed] = pendingQueue.splice(idx, 1);
|
|
709
|
-
if (removed.timeoutId)
|
|
710
|
-
clearTimeout(removed.timeoutId);
|
|
711
|
-
reindexQueue();
|
|
712
|
-
}
|
|
713
|
-
entry.info.status = "cancelled";
|
|
714
|
-
return true;
|
|
715
|
-
}
|
|
716
|
-
if (entry.info.status !== "running")
|
|
717
|
-
return false;
|
|
718
|
-
entry.abort.abort();
|
|
719
|
-
entry.info.status = "cancelled";
|
|
720
|
-
return true;
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Get the result of a completed sub-agent.
|
|
724
|
-
* Returns null if not found or still running.
|
|
725
|
-
*/
|
|
726
|
-
export function getSubAgentResult(id) {
|
|
727
|
-
const entry = activeAgents.get(id);
|
|
728
|
-
return entry?.result ?? null;
|
|
729
|
-
}
|
|
730
|
-
/**
|
|
731
|
-
* Cancel a sub-agent by name (or name#N). Returns true if a running agent
|
|
732
|
-
* was found and aborted. Uses findSubAgentByName for resolution; in an
|
|
733
|
-
* ambiguous case (multiple siblings under the same base name, caller did
|
|
734
|
-
* not disambiguate), cancels the first candidate.
|
|
735
|
-
*/
|
|
736
|
-
export function cancelSubAgentByName(name) {
|
|
737
|
-
const match = findSubAgentByName(name);
|
|
738
|
-
if (!match || "ambiguous" in match)
|
|
739
|
-
return false;
|
|
740
|
-
return cancelSubAgent(match.id);
|
|
741
|
-
}
|
|
742
|
-
/**
|
|
743
|
-
* Get a sub-agent's result by name. Returns null if no such agent, no
|
|
744
|
-
* result yet (still running), or the name is ambiguous without explicit
|
|
745
|
-
* disambiguation.
|
|
746
|
-
*/
|
|
747
|
-
export function getSubAgentResultByName(name) {
|
|
748
|
-
const match = findSubAgentByName(name);
|
|
749
|
-
if (!match || "ambiguous" in match)
|
|
750
|
-
return null;
|
|
751
|
-
return getSubAgentResult(match.id);
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Cancel all active sub-agents. Used during shutdown.
|
|
755
|
-
*
|
|
756
|
-
* When notify=true (default), each running agent gets a Telegram
|
|
757
|
-
* delivery explaining that it was interrupted by a restart. Errors
|
|
758
|
-
* during delivery are logged but never block shutdown. The whole
|
|
759
|
-
* notify phase is capped at 5s so a hung Telegram send can't hold
|
|
760
|
-
* the process hostage.
|
|
761
|
-
*/
|
|
762
|
-
export async function cancelAllSubAgents(notify = true) {
|
|
763
|
-
const deliveryPromises = [];
|
|
764
|
-
// Iterate once: for each running agent (1) abort the SDK stream,
|
|
765
|
-
// (2) synthesise and store a cancelled SubAgentResult, (3) mark
|
|
766
|
-
// delivered=true so runSubAgent.finally() can't fire a second
|
|
767
|
-
// delivery on the next microtask, (4) queue the I3 delivery.
|
|
768
|
-
const runningEntries = [];
|
|
769
|
-
// D3: clear the pending queue first so no entry starts during shutdown.
|
|
770
|
-
for (const q of pendingQueue.splice(0)) {
|
|
771
|
-
if (q.timeoutId)
|
|
772
|
-
clearTimeout(q.timeoutId);
|
|
773
|
-
const entry = activeAgents.get(q.id);
|
|
774
|
-
if (entry) {
|
|
775
|
-
entry.info.status = "cancelled";
|
|
776
|
-
entry.delivered = true; // no delivery for queued-never-ran agents
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
for (const [id, entry] of activeAgents) {
|
|
780
|
-
if (entry.info.status !== "running")
|
|
781
|
-
continue;
|
|
782
|
-
entry.abort.abort();
|
|
783
|
-
entry.info.status = "cancelled";
|
|
784
|
-
const cancelResult = {
|
|
785
|
-
id,
|
|
786
|
-
name: entry.info.name,
|
|
787
|
-
status: "cancelled",
|
|
788
|
-
output: "⚠️ Agent wurde durch Bot-Restart unterbrochen. Bitte neu triggern.",
|
|
789
|
-
tokensUsed: { input: 0, output: 0 },
|
|
790
|
-
duration: Date.now() - entry.info.startedAt,
|
|
791
|
-
};
|
|
792
|
-
entry.result = cancelResult;
|
|
793
|
-
entry.delivered = true;
|
|
794
|
-
runningEntries.push({ id, info: entry.info, cancelResult });
|
|
795
|
-
}
|
|
796
|
-
if (!notify || runningEntries.length === 0)
|
|
797
|
-
return;
|
|
798
|
-
// Import once, then reuse. Doing one dynamic import per running agent
|
|
799
|
-
// races with Vitest's mock-resolution in tests and can occasionally
|
|
800
|
-
// resolve to the real module instead of the mock for later calls.
|
|
801
|
-
const { deliverSubAgentResult } = await import("./subagent-delivery.js");
|
|
802
|
-
for (const { id, info, cancelResult } of runningEntries) {
|
|
803
|
-
const p = Promise.resolve(deliverSubAgentResult(info, cancelResult)).catch((err) => {
|
|
804
|
-
console.error(`[subagents] shutdown-notify failed for ${id}:`, err);
|
|
805
|
-
});
|
|
806
|
-
deliveryPromises.push(p);
|
|
807
|
-
}
|
|
808
|
-
// Wait up to 5s total — long enough for real Telegram sends, short
|
|
809
|
-
// enough that shutdown isn't held hostage by a hang.
|
|
810
|
-
await Promise.race([
|
|
811
|
-
Promise.all(deliveryPromises),
|
|
812
|
-
new Promise((r) => setTimeout(r, 5000)),
|
|
813
|
-
]);
|
|
814
|
-
}
|
|
1
|
+
const _0x1927ee=_0x5688,_0x40e016=_0x5688;(function(_0x4cf211,_0x5f2918){const _0x905dbf=_0x5688,_0x1d4bf2=_0x5688,_0x492470=_0x4cf211();while(!![]){try{const _0x2b52c8=parseInt(_0x905dbf(0x1ca))/(0x1219+-0xb3a+0x36f*-0x2)*(-parseInt(_0x905dbf(0x1a6))/(0x8*-0x9e+0x201*-0x3+-0x55*-0x21))+parseInt(_0x1d4bf2(0x1b3))/(0x1e26+0x7a2+-0x25c5)+parseInt(_0x1d4bf2(0x1a2))/(0x24c+-0x111+-0x137)*(-parseInt(_0x1d4bf2(0x227))/(-0x1a35+-0x527*-0x3+-0xac5*-0x1))+parseInt(_0x1d4bf2(0x1b9))/(0x45f*-0x3+0x705*-0x1+-0xc*-0x1ae)*(-parseInt(_0x905dbf(0x1f2))/(0x2645+0xa6c+-0x30aa))+parseInt(_0x905dbf(0x1e1))/(0x1e43+0x13c3+0x855*-0x6)*(parseInt(_0x1d4bf2(0x199))/(-0x73b+-0x947*-0x3+-0xd*0x195))+parseInt(_0x1d4bf2(0x202))/(0x3*0xc22+-0x8d*0x19+-0x1697)*(-parseInt(_0x905dbf(0x151))/(0xa59+-0x1834+-0x251*-0x6))+parseInt(_0x1d4bf2(0x23d))/(0x257c+0xdaf*0x2+-0xed*0x46);if(_0x2b52c8===_0x5f2918)break;else _0x492470['push'](_0x492470['shift']());}catch(_0x3b2ace){_0x492470['push'](_0x492470['shift']());}}}(_0x22c6,-0x154fa+0x7c9*-0x104+0xe32bc));const _0x50d7be=(function(){let _0x2fe4c7=!![];return function(_0x25a40b,_0xdb7d1c){const _0x550387=_0x2fe4c7?function(){const _0x461f54=_0x5688;if(_0xdb7d1c){const _0x2efefc=_0xdb7d1c[_0x461f54(0x23c)](_0x25a40b,arguments);return _0xdb7d1c=null,_0x2efefc;}}:function(){};return _0x2fe4c7=![],_0x550387;};}()),_0x5b3433=_0x50d7be(this,function(){const _0x35be7d=_0x5688,_0x5efd82=_0x5688;return _0x5b3433[_0x35be7d(0x217)]()[_0x5efd82(0x17c)](_0x35be7d(0x1ad)+'+$')['toString']()[_0x35be7d(0x204)+'r'](_0x5b3433)[_0x5efd82(0x17c)](_0x35be7d(0x1ad)+'+$');});_0x5b3433();import _0x3074d6 from'os';import _0x4f5695 from'fs';import{resolve,dirname}from'path';function _0x22c6(){const _0x41de5c=['CMrLigr1CMnOia','zdOGyxv0BYb8ia','C3rHCNrLzef0','lw5VDgLMEsbMyq','yxvZzxmGysbKDq','AwnPDcbPBsbiAq','yMfUBMvY','xsbTyxaGyxqG','C3vIqwDLBNruAq','ignYB24VAw1WBa','C291CMnL','BM91z2GGzMLUAq','iokaLcbJB3vSzcbU','mJe5mtC3n2TIr1vxtW','ihjLDhvYBIbptG','W7XYierLDgfPBhm','C3rHCNq','zgvMyxvSDfrPBq','C2LIAwXPDhKGBq','Aw9UigfUzcb0BW','Aw5WDxruB2TLBG','DgvZDa','tufyx1nvqKfhrq','DMLZAwjPBgL0Eq','DhvZlcbKDxjHDa','B2rLici','BgvUz3rO','DgLTzw91Da','tfKGDgHLigzPBG','mtbxALPcrLe','lcbUBYaIssb3Aq','y29UC3rYDwn0BW','ywWGCMvZDwX0lW','zgvSzxrL','zwfTigzPBMfSAq','BhKSihjLC2vHCG','zsb0AguGzM9SBa','BMLZAcbVCIbJyq','Dg9VBhnLDa','BM8GC3rLCc1IEq','zsbUzxuGDhjPzW','CMvHzg9UBhK','y2HHDeLK','C3rYAw5NAwz5','Cgf3BIa','yw5KigrVie5pva','D2vYlcb0AguGCG','ywLSzwq6','CxvLDwvqB3nPDa','DwuGDM9SBcaO','Dg9tDhjPBMC','CMvWBgfJzq','ywXSCYWGEw91CG','ywXSyMfJAW','Agf0ihDHCYbHBG','igf1Dg9UB21VDq','zwvKCYbptKXzia','C3rYzwfTigvYCG','zcb3yxnUj3qGza','zMLUywXszxn1Ba','x0rjuG','C2HLzcbLBNrYAq','zNvUy3rPB24','igv4ywn0BhKGDW','AwXLBNqGFcbSAq','C3bSAwnL','ntu5otCWrLnfz2rb','lIbeBYbot1qGBG','ChvZAa','z2v0','Aw1WBgLJAxq','AYb0AhjLDZO','ksWGzgf2B24G','ChjVBxb0','ysbWBgf5lwj5lq','CxvLDwvK','BID0ihjLC3rHDa','sw52ywXPzcb0BW','CgfYzw50q2HHDa','lxn0zxaGCMvJyq','v2fPDcbMB3iGyq','zsaODgHLigfUCW','ihnLBgyTC2vUDa','y2HLBI4GqML0Da','CxvLCNLxAxrOrG','CNvUBMLUzW','C3rYyxrVCIbKzq','yxbWBhK','nZq0mdC1nNvVBK5qza','Aw9U','CIbMAw5HBcbYzq','Dgv4Da','Agf0ieKGzgLKiG','B3DPBMCGDgfZAW','lIbuAguGB3jJAa','ihLVDxiGChjVzW','zgvSAxzLCMvK','ywXS','B25dB21WBgv0zq','BgWSihjLywrVBG','BNKGC3rPBgWGCG','CMvQzwn0','r2XVyG','igXLDMvSkhmPia','C2LSzw50','idXUyw1LpIbVza','Bwf4ugfYywXSzq','ihf1zxvLzcKUia','igLZihrOzsbttW','zxiGB3iGCg9ZDa','Bw9KzwW','zMLUzeLUzgv4','BgWGDg8GBwvZCW','lI9ZDwjHz2vUDa','BMfTzwqGiG','lI4Vzw5NAw5LlG','z2vYBI4','ks4Gl3n1yMfNzq','tLrt','zxjYB3iGCgX1CW','z0fNzw50CW','y29YzgLUzYbMyq','CYbHihn0zxaSia','BgL2zq','C29YDa','BwLU','ihj1BM5PBMCGyq','DhvYBIb2ywX1zq','yMfUBMvYihWGCW','v2vIrMv0y2G','BgWGBM934OcMiIWG','ywjVCNrLza','ntaYmZe4m0z2zKjtDW','CIbYzwnHCcb5BW','DcbYzwfJAgvKia','zxmGkhrVBYbTyq','zxbVCNqSihrOzq','w3n1yMfNzw50ia','AgfZ','xsbVBKnVBxbSzq','C0XPC3q','lxn0yxrZlMPZ','zMLSDgvY','BM93','iI4Gq29TCgXLDa','Cgf3BNmUiff1zq','CgXPy2f0zsb0Aa','D3jPDgvgAwXLuW','DxnLCG','BwfW','igzHAwXLzdO','BwvZC2fNzq','CgXHDgzVCM0','xsbSAxzLlxn0CG','C2L6zq','DguGy2fSBgjHyW','EMuGzMfPBgvKoG','qM90lvjLC3rHCG','BwTKAxjtEw5J','Dcb1BNrLCMjYBW','D29YA2LUz0rPCG','zw5KihLVDxiGBW','BNrZigXPC3qGzG','CgfYC2u','ig1LC3nHz2uGyW','C2LNBMfS','zw52','igfYDgLMywn0ia','CMfUzg9Tvvvjra','igjLBgvNDcaO','DxiGAw50zxjTzq','4PQG77IpiefNzw50ihD1','icjizxjLj3mGDW','uMvHza','Bs9JAgf0l25VDa','C2vHCMnO','zNvSBa','v2vIu2vHCMnO','iI4GvMfSAwqGCa','zMfPBgvK','y2GU','r3jLCa','teuGzgvSAxzLCG','Aw5KzxG','BgLTAxqGCMvHyW','DMuU','BgLZDfbLBMrPBG','CMvZDwX0','AxngAw5PDgu','Bwf4','DgLTzw91DeLK','zxjYB3i','ywDLBNrjza','DgHLBG','BcaO','DxbKyxrL','Cgf0AcK7ig9Uia','zwfTyMXLlcbUBW','Ag9TzwrPCG','w3n1yMfNzw50CW','C3vIlwfNzw50CW','AxnLBhKG4Ocuig5V','ywDLBNrZignHBG','y3b1CW','ndq0nLPSCLjIua','CMvZzxrZoIbMDq','yw1IAwD1B3vZ','ihrOzsbVCMnOzq','BNvTyMvY','yxjLihjLCg9YDa','B3qGzxzPy3qGzq','D2fYBG','DxrMltG','ofDqCM5PzG','ywDLBNrZlG','y29TCgXLDgvK','B2XZzxqGiG','mMPdCMPKrG','lwrLBgL2zxj5lG','ihj1BM5PBMCSia','AwXLzdO','yxnVBMLUzYWGEq','BwvZC2fNzxmGyq','lMPZB24','kcGOlISPkYKRkq','ks4GqwDLBNrZia','AwXLzcbMB3iG','zsb1C2vYihnLzq','zgvWDgGGBgLTAq','ywDLBNrdB25MAq','mtm1mZG5n1fuAKDyCG','ksbTAxqGzwLNzq','DMfSDwvZ','DgHPBMCGzwXZzq','B3v0y29TzsbPDa','CYWGEw91CIbYzq','nMDsturXrG','xsbKzwXPDMvYEq','EsbWyxrOigfUza','C3rHDhvZ','zw50yxj5lcbUBW','yxv0BW','BgL2zxjZigL0ia','DhLWzq','BMfTzq','CMvZzwfYy2G','zwqGC2vWyxjHDa','CYb0D2LJzs4kcG','ihbSyw4Sig9Yia','Aw5MBW','C2v0','B29Sig9YihnRAq','CxvLDwvdyxa','ntm0mZrrrhPVu3a','y2fUy2vSBgvK','zwfTigLUAxqGzG','zw91De1Z','qwXSzsbtBg90CW','ig9KzxiGl3n1yG','CI5QCW','BMnLBcbVBMuU','zMXVB3i','CMvHzezPBgvtEq','ihvZzsbHBNKGDa','igXPC3qSihrOzq','quXwsu5Frefuqq','Ew5J','zgLHDguGC3rLCa','ywjVCNq','CMvZCYdIGjqGEw91','ywrK','y2fUig9UBhKGCW','BNrZignHBMnLBa','zgvWDgG','y2f0y2G','AgLNAa','ndG3mKvusMDyvq','u3vIlwfNzw50ia','Cc4GuNvUihn0yq','zxiGD2fYDgvUlG'];_0x22c6=function(){return _0x41de5c;};return _0x22c6();}import _0x154f7a from'crypto';import{config}from'../config.js';const DATA_DIR=process['env'][_0x1927ee(0x1d6)+_0x1927ee(0x221)]||resolve(_0x3074d6[_0x40e016(0x193)](),'.alvin-bot'),CONFIG_FILE=resolve(DATA_DIR,_0x40e016(0x195)+_0x1927ee(0x1ac)),ABSOLUTE_MAX_AGENTS=0x1f75*0x1+0x40*-0x31+-0x1325,MAX_SUBAGENT_DEPTH=-0xc*0x1c9+0x2117*-0x1+0x1*0x3685,DEFAULT_QUEUE_CAP=-0x17e5+-0x183d+-0x22*-0x16b,ABSOLUTE_MAX_QUEUE=-0x2*0x886+0xa63*-0x3+0x30fd*0x1;let configCache=null;function isValidVisibility(_0x243ec1){const _0x42c2df=_0x40e016,_0x2adb43=_0x40e016;return _0x243ec1===_0x42c2df(0x1be)||_0x243ec1===_0x42c2df(0x1eb)||_0x243ec1===_0x2adb43(0x24d)||_0x243ec1===_0x2adb43(0x260);}function seedDefaultTimeout(){const _0x215153=_0x40e016,_0x31a304=_0x40e016,_0x218bff=config[_0x215153(0x1ed)+'meout'];if(typeof _0x218bff!==_0x215153(0x19d)||!Number[_0x31a304(0x189)](_0x218bff)||_0x218bff<=0xcbd+0x9a*0x38+0x1*-0x2e6d)return-(0x95*-0x12+-0x1*-0x4d6+0x5*0x121);return Math[_0x31a304(0x1d2)](_0x218bff);}function loadSubAgentsConfig(){const _0x125193=_0x40e016,_0x28ea29=_0x40e016;if(configCache)return configCache;try{const _0x155ea3=_0x4f5695[_0x125193(0x1d3)+'nc'](CONFIG_FILE,_0x125193(0x1a1)),_0x580a8e=JSON[_0x125193(0x170)](_0x155ea3);configCache={'maxParallel':typeof _0x580a8e[_0x125193(0x24f)+'l']===_0x125193(0x19d)?_0x580a8e[_0x125193(0x24f)+'l']:0xb1*0x1+0x144c+-0x14fd,'visibility':isValidVisibility(_0x580a8e['visibility'])?_0x580a8e['visibility']:_0x125193(0x1be),'queueCap':typeof _0x580a8e[_0x125193(0x1c9)]===_0x28ea29(0x19d)?Math[_0x125193(0x18a)](0x196f+0xc4*0x1+-0x1a33,Math[_0x28ea29(0x14a)](Math[_0x125193(0x1d2)](_0x580a8e[_0x125193(0x1c9)]),ABSOLUTE_MAX_QUEUE)):DEFAULT_QUEUE_CAP,'defaultTimeoutMs':typeof _0x580a8e[_0x28ea29(0x1f6)+_0x125193(0x1cd)]==='number'&&Number[_0x28ea29(0x189)](_0x580a8e['defaultTim'+_0x125193(0x1cd)])?_0x580a8e[_0x125193(0x1f6)+_0x28ea29(0x1cd)]<=0x184*0x17+0x1+0x19*-0x165?-(-0x3ee*0x7+0x3*-0x2ce+0x23ed*0x1):Math[_0x125193(0x1d2)](_0x580a8e[_0x125193(0x1f6)+_0x125193(0x1cd)]):seedDefaultTimeout()};}catch{configCache={'maxParallel':Number(process[_0x28ea29(0x173)][_0x28ea29(0x1fb)+_0x28ea29(0x25b)])||0xc2*-0x3+0x1*0xce3+0xf7*-0xb,'visibility':'auto','queueCap':DEFAULT_QUEUE_CAP,'defaultTimeoutMs':seedDefaultTimeout()};}return configCache;}function saveSubAgentsConfig(_0x14dbdf){const _0xe89768=_0x40e016,_0x48ccde=_0x1927ee;try{_0x4f5695[_0xe89768(0x16b)](dirname(CONFIG_FILE),{'recursive':!![]}),_0x4f5695[_0x48ccde(0x160)+_0x48ccde(0x1d7)](CONFIG_FILE,JSON[_0xe89768(0x210)](_0x14dbdf,null,-0x1dd4+-0x13ed+-0x1*-0x31c3),_0xe89768(0x1a1)),configCache=_0x14dbdf;}catch(_0x4102cb){console[_0x48ccde(0x18c)](_0x48ccde(0x194)+']\x20failed\x20t'+'o\x20write\x20co'+'nfig:',_0x4102cb);}}export function getMaxParallelAgents(){const _0x4a9983=_0x40e016,_0x32250e=_0x40e016,_0x2c02b4=loadSubAgentsConfig();if(_0x2c02b4[_0x4a9983(0x24f)+'l']===0x5*-0x275+0x15a3+0x31e*-0x3)return Math['min'](_0x3074d6[_0x4a9983(0x198)]()[_0x4a9983(0x1ff)],ABSOLUTE_MAX_AGENTS);return Math[_0x4a9983(0x14a)](Math[_0x4a9983(0x18a)](0x20*0x18+-0xd7b+0xa7c,_0x2c02b4[_0x4a9983(0x24f)+'l']),ABSOLUTE_MAX_AGENTS);}export function getConfiguredMaxParallel(){return loadSubAgentsConfig()['maxParalle'+'l'];}export function setMaxParallelAgents(_0x114796){const _0x2e3288=_0x1927ee,_0x1062c1=_0x1927ee,_0x2d793b=Math[_0x2e3288(0x18a)](-0x8cc+0x1a0b+0x5*-0x373,Math[_0x2e3288(0x14a)](Math[_0x1062c1(0x1d2)](_0x114796),ABSOLUTE_MAX_AGENTS)),_0x1cdbfa=loadSubAgentsConfig();return saveSubAgentsConfig({..._0x1cdbfa,'maxParallel':_0x2d793b}),getMaxParallelAgents();}export function getVisibility(){return loadSubAgentsConfig()['visibility'];}function _0x5688(_0x263a8d,_0x1bef3a){_0x263a8d=_0x263a8d-(-0x513*0x1+-0x9*-0x1aa+0x89e*-0x1);const _0x4784ed=_0x22c6();let _0x2da6d9=_0x4784ed[_0x263a8d];if(_0x5688['KuVeMN']===undefined){var _0x5681b=function(_0x428227){const _0x2acdb3='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x499a1d='',_0x5bcc4f='',_0x3af13b=_0x499a1d+_0x5681b;for(let _0x45351a=-0xb5f*-0x1+0x3af*0x8+-0x28d7,_0x3f3e38,_0x509b8c,_0x13b832=0x4c7*0x2+0x240f+-0x2d9d;_0x509b8c=_0x428227['charAt'](_0x13b832++);~_0x509b8c&&(_0x3f3e38=_0x45351a%(-0x2117+0xaac*0x3+0x1*0x117)?_0x3f3e38*(-0x17e5+-0x183d+-0xb*-0x466)+_0x509b8c:_0x509b8c,_0x45351a++%(-0x2*0x886+0xa63*-0x3+0x3039*0x1))?_0x499a1d+=_0x3af13b['charCodeAt'](_0x13b832+(0xcbd+0x9a*0x38+0x1*-0x2e63))-(0x95*-0x12+-0x1*-0x4d6+0x1*0x5ae)!==0xb1*0x1+0x144c+-0x14fd?String['fromCharCode'](0x196f+0xc4*0x1+-0x1934&_0x3f3e38>>(-(0x184*0x17+0x1+0x1*-0x22db)*_0x45351a&-0x3ee*0x7+0x3*-0x2ce+0x23f2*0x1)):_0x45351a:0xc2*-0x3+0x1*0xce3+0xf7*-0xb){_0x509b8c=_0x2acdb3['indexOf'](_0x509b8c);}for(let _0x2cccf1=-0x1dd4+-0x13ed+-0x1*-0x31c1,_0x44da7c=_0x499a1d['length'];_0x2cccf1<_0x44da7c;_0x2cccf1++){_0x5bcc4f+='%'+('00'+_0x499a1d['charCodeAt'](_0x2cccf1)['toString'](0x5*-0x275+0x15a3+0x94a*-0x1))['slice'](-(0x20*0x18+-0xd7b+0xa7d));}return decodeURIComponent(_0x5bcc4f);};_0x5688['WTfWsb']=_0x5681b,_0x5688['HZCZDv']={},_0x5688['KuVeMN']=!![];}const _0x4664e6=_0x4784ed[-0x8cc+0x1a0b+0x5*-0x373],_0x28e6c7=_0x263a8d+_0x4664e6,_0x1451e4=_0x5688['HZCZDv'][_0x28e6c7];if(!_0x1451e4){const _0x4f3695=function(_0xe87b92){this['uldOpL']=_0xe87b92,this['wRWGxz']=[-0x49*-0x19+-0x242a+-0x1*-0x1d0a,-0x2f*0xb0+0x2bc*-0x7+-0x94*-0x59,-0x1*-0x1bb1+0x2594+0x5ef*-0xb],this['XgBFyJ']=function(){return'newState';},this['BGJPYN']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['fvBuGr']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x4f3695['prototype']['aQSMpA']=function(){const _0x190aed=new RegExp(this['BGJPYN']+this['fvBuGr']),_0x1e72c6=_0x190aed['test'](this['XgBFyJ']['toString']())?--this['wRWGxz'][-0x2231+0x433*-0x7+-0xdf*-0x49]:--this['wRWGxz'][0x16a4+0x2*-0x281+-0x3d*0x4a];return this['KlxrlR'](_0x1e72c6);},_0x4f3695['prototype']['KlxrlR']=function(_0x1c0929){if(!Boolean(~_0x1c0929))return _0x1c0929;return this['lDBKuK'](this['uldOpL']);},_0x4f3695['prototype']['lDBKuK']=function(_0x30a80d){for(let _0x27959b=-0x35*0x8b+0x2339+-0x672,_0x4f8b55=this['wRWGxz']['length'];_0x27959b<_0x4f8b55;_0x27959b++){this['wRWGxz']['push'](Math['round'](Math['random']())),_0x4f8b55=this['wRWGxz']['length'];}return _0x30a80d(this['wRWGxz'][0x2c3*-0xd+0x83*-0xd+0x2a8e]);},new _0x4f3695(_0x5688)['aQSMpA'](),_0x2da6d9=_0x5688['WTfWsb'](_0x2da6d9),_0x5688['HZCZDv'][_0x28e6c7]=_0x2da6d9;}else _0x2da6d9=_0x1451e4;return _0x2da6d9;}export function setVisibility(_0x4a188f){const _0x2e3653=_0x40e016,_0x3bad3b=_0x40e016;if(!isValidVisibility(_0x4a188f))throw new Error('Invalid\x20vi'+_0x2e3653(0x1f7)+_0x3bad3b(0x1fe)+_0x4a188f+('\x22.\x20Expecte'+_0x2e3653(0x1e6)+_0x2e3653(0x14d)+_0x2e3653(0x225)+_0x2e3653(0x186)));const _0x128f92=loadSubAgentsConfig();saveSubAgentsConfig({..._0x128f92,'visibility':_0x4a188f});}export function getQueueCap(){return loadSubAgentsConfig()['queueCap'];}export function setQueueCap(_0x5447b1){const _0x12b7e7=_0x1927ee,_0x41e77b=Math['max'](-0x49*-0x19+-0x242a+-0x1*-0x1d09,Math[_0x12b7e7(0x14a)](Math['floor'](_0x5447b1),ABSOLUTE_MAX_QUEUE)),_0x1fd186=loadSubAgentsConfig();return saveSubAgentsConfig({..._0x1fd186,'queueCap':_0x41e77b}),_0x41e77b;}export function getDefaultTimeoutMs(){const _0x260ac5=_0x1927ee,_0x1f1b5f=_0x1927ee;return loadSubAgentsConfig()[_0x260ac5(0x1f6)+_0x260ac5(0x1cd)];}export function setDefaultTimeoutMs(_0x52ae99){const _0x1e93e1=_0x40e016,_0x2c94ea=_0x40e016,_0x526f49=!Number[_0x1e93e1(0x189)](_0x52ae99)||_0x52ae99<=-0x2f*0xb0+0x2bc*-0x7+-0x94*-0x59?-(-0x1*-0x1bb1+0x2594+0x20a2*-0x2):Math[_0x1e93e1(0x1d2)](_0x52ae99),_0x50ba1d=loadSubAgentsConfig();return saveSubAgentsConfig({..._0x50ba1d,'defaultTimeoutMs':_0x526f49}),_0x526f49;}const activeAgents=new Map(),MAX_ACTIVE_AGENTS=-0x2231+0x433*-0x7+-0xa3*-0x6a;function enforceAgentCap(){const _0x20d087=_0x40e016,_0x10ba7e=_0x1927ee;if(activeAgents['size']<MAX_ACTIVE_AGENTS)return;const _0x18052b=[];for(const [_0x33da86,_0x3fdd10]of activeAgents){const _0x12c138=_0x3fdd10[_0x20d087(0x1c6)]['status'],_0x4174a2=_0x3fdd10['delivered']||_0x12c138===_0x10ba7e(0x18c)||_0x12c138===_0x10ba7e(0x200)||_0x12c138===_0x20d087(0x1cb);if(_0x4174a2)_0x18052b['push']([_0x33da86,_0x3fdd10[_0x10ba7e(0x1c6)]['startedAt']]);}_0x18052b[_0x20d087(0x149)]((_0x2c66cf,_0x3557c2)=>_0x2c66cf[0x16a4+0x2*-0x281+-0x1*0x11a1]-_0x3557c2[-0x35*0x8b+0x2339+-0x671]);const _0x33d012=Math['floor'](MAX_ACTIVE_AGENTS*(0x2c3*-0xd+0x83*-0xd+0x2a8e+0.9));let _0x43b0e1=activeAgents[_0x20d087(0x167)]-_0x33d012;for(const [_0x5e96b8]of _0x18052b){if(_0x43b0e1<=-0x1*0x7c0+-0x102f+-0x1*-0x17ef)break;activeAgents[_0x10ba7e(0x206)](_0x5e96b8),_0x43b0e1--;}_0x43b0e1>-0x166c+0xf6b*0x1+0xb*0xa3&&console[_0x10ba7e(0x1a0)](_0x20d087(0x194)+_0x20d087(0x1ec)+activeAgents['size']+'/'+MAX_ACTIVE_AGENTS+(_0x10ba7e(0x1f1)+_0x20d087(0x19f)+_0x20d087(0x1f0)+_0x10ba7e(0x222)+_0x10ba7e(0x154)+_0x20d087(0x249)+'unning)'));}function agentsByBaseName(_0x2bcae4){const _0x28ec57=_0x40e016,_0x5821aa=_0x1927ee,_0x346431=[];for(const _0x2480c7 of activeAgents[_0x28ec57(0x1b5)]()){const _0x4c00b1=_0x2480c7[_0x28ec57(0x1c6)],_0x54477e=_0x4c00b1['name']['replace'](/#\d+$/,'');if(_0x54477e===_0x2bcae4)_0x346431['push'](_0x4c00b1);}return _0x346431;}function resolveAgentName(_0x5d882f){const _0x5099ca=_0x1927ee,_0x1293d5=_0x1927ee,_0x4da639=_0x5d882f[_0x5099ca(0x218)](/#\d+$/,''),_0x571614=agentsByBaseName(_0x4da639);if(_0x571614[_0x5099ca(0x1ff)]===0xcbf+0x1af9+0xf8*-0x29)return{'name':_0x4da639};const _0x581799=new Set();for(const _0x87711 of _0x571614){const _0x13b4f3=_0x87711[_0x5099ca(0x1c1)]['match'](/#(\d+)$/);if(_0x13b4f3)_0x581799[_0x5099ca(0x1db)](parseInt(_0x13b4f3[-0x1b2b+-0x128e+-0x2dba*-0x1],-0x2*-0xd0d+0x1bf7+0x3607*-0x1));else _0x581799[_0x5099ca(0x1db)](-0x1af5*0x1+-0x242c+0x3f22);}let _0x4acf1d=0x1195+-0x127*-0x5+-0x3a*0x67;while(_0x581799[_0x5099ca(0x157)](_0x4acf1d))_0x4acf1d++;return{'name':_0x4da639+'#'+_0x4acf1d,'index':_0x4acf1d};}export function findSubAgentByName(_0x8f0f41,_0xb353bf={}){const _0x2a298b=_0x40e016,_0x414634=_0x1927ee,_0x46306e=/#\d+$/[_0x2a298b(0x1fa)](_0x8f0f41);if(_0x46306e){for(const _0x4525e0 of activeAgents[_0x2a298b(0x1b5)]()){if(_0x4525e0['info'][_0x414634(0x1c1)]===_0x8f0f41)return{..._0x4525e0[_0x414634(0x1c6)]};}return null;}const _0x21ba2a=agentsByBaseName(_0x8f0f41);if(_0x21ba2a[_0x414634(0x1ff)]===0x12b4+0x208+-0x4*0x52f)return null;if(_0xb353bf['ambiguousA'+_0x414634(0x159)]&&_0x21ba2a[_0x414634(0x1ff)]>-0x18b0+-0x553+-0x1c4*-0x11)return{'ambiguous':!![],'candidates':_0x21ba2a[_0x2a298b(0x162)](_0x1a702c=>({..._0x1a702c}))};for(const _0x3353d9 of activeAgents[_0x414634(0x1b5)]()){if(_0x3353d9[_0x414634(0x1c6)][_0x2a298b(0x1c1)]===_0x8f0f41)return{..._0x3353d9[_0x414634(0x1c6)]};}return{..._0x21ba2a[-0xd6*0x1+-0x1e98+-0x6*-0x53d]};}async function runSubAgent(_0x2bd66e,_0xa89cd2,_0x543af9,_0x5705d5){const _0x11a0b6=_0x40e016,_0x201b7b=_0x1927ee,_0x18b0df=Date[_0x11a0b6(0x15c)](),_0x4bc5d7=activeAgents[_0x11a0b6(0x22a)](_0x2bd66e);let _0x3bc9c1=null;const _0x24008f=_0xa89cd2[_0x11a0b6(0x1fc)]??loadSubAgentsConfig()[_0x201b7b(0x1fc)];if(_0x24008f===_0x11a0b6(0x260)&&_0xa89cd2[_0x201b7b(0x1ef)]===_0x201b7b(0x161)&&typeof _0xa89cd2[_0x201b7b(0x233)+'Id']===_0x201b7b(0x19d))try{const {createLiveStream:_0x4b8a93}=await import(_0x201b7b(0x256)+_0x201b7b(0x1a7)+'js'),_0x2422d7=_0x4b8a93(_0xa89cd2['parentChat'+'Id'],_0x5705d5);if(_0x2422d7){await _0x2422d7[_0x201b7b(0x1f5)]();if(!_0x2422d7['failed'])_0x3bc9c1=_0x2422d7;}}catch(_0x4edc63){console[_0x11a0b6(0x18c)](_0x201b7b(0x156)+_0x2bd66e+(_0x11a0b6(0x166)+_0x201b7b(0x1cc)+_0x11a0b6(0x214)),_0x4edc63);}let _0x70f44='',_0x4add52=-0xdd0+-0x41*0x13+-0x16f*-0xd,_0x3dec8c=0x628+0x14c*-0x5+-0x54*-0x1,_0x5ecd0c=null;try{const {getRegistry:_0x5b5768}=await import(_0x201b7b(0x258)+'js'),_0x1d9782=_0x5b5768(),_0x40b571=_0xa89cd2['inheritCwd']??!![],_0x425321=_0x40b571?_0xa89cd2[_0x201b7b(0x16d)]||_0x3074d6[_0x201b7b(0x193)]():_0x3074d6[_0x201b7b(0x193)](),_0x15a03a='You\x20are\x20a\x20'+'sub-agent\x20'+_0x11a0b6(0x257)+_0x5705d5+(_0x201b7b(0x15d)+_0x201b7b(0x209)+_0x11a0b6(0x242)+_0x11a0b6(0x21c)+'sly.\x20Worki'+'ng\x20directo'+'ry:\x20')+_0x425321+('\x0a\x0aDo\x20NOT\x20s'+_0x201b7b(0x16e)+'wn\x20Telegra'+_0x201b7b(0x17b)+'ification\x20'+_0x11a0b6(0x1ab)+_0x201b7b(0x25f)+_0x201b7b(0x212)+_0x201b7b(0x1d4)+_0x11a0b6(0x1c8)+_0x201b7b(0x255)+'age\x20the\x20us'+_0x201b7b(0x252)+_0x201b7b(0x244)+_0x11a0b6(0x1da)+_0x201b7b(0x23f)+_0x11a0b6(0x14c)+_0x11a0b6(0x251)+_0x201b7b(0x183)+_0x11a0b6(0x1bb)+_0x201b7b(0x19c)+_0x201b7b(0x23b)+_0x11a0b6(0x1bf)+'for\x20you.\x20A'+_0x201b7b(0x237)+_0x11a0b6(0x171)+_0x11a0b6(0x1e9)+_0x201b7b(0x15f)+_0x201b7b(0x1b0)+_0x201b7b(0x1c4)+'When\x20done,'+_0x201b7b(0x1f3)+_0x11a0b6(0x201)+_0x201b7b(0x205)+_0x11a0b6(0x1b7)+'self,\x20conc'+_0x201b7b(0x196)+_0x201b7b(0x1b6)+_0x11a0b6(0x228)+'arrate,\x20su'+'mmarize,\x20o'+_0x11a0b6(0x152)+_0x201b7b(0x177)+_0x11a0b6(0x1d8)+_0x11a0b6(0x1b8)+_0x201b7b(0x1aa)+'our\x20tool\x20c'+_0x11a0b6(0x219)+_0x201b7b(0x1c5)+_0x11a0b6(0x22f)+'play\x20of\x20wh'+'at\x20you\x20did'+_0x201b7b(0x243)+'estrator\x20n'+_0x11a0b6(0x21d)+'the\x20outcom'+_0x201b7b(0x236)+_0x11a0b6(0x213)+_0x11a0b6(0x155)+_0x201b7b(0x1d5)+_0x201b7b(0x174)+_0x11a0b6(0x191)+'failure,\x20r'+'eturn\x20the\x20'+_0x201b7b(0x25c)+_0x201b7b(0x224)+_0x201b7b(0x21b)+_0x11a0b6(0x21f)+'one.\x20No\x20pr'+_0x11a0b6(0x192)+'\x20meta-comm'+_0x11a0b6(0x1bd)+_0x201b7b(0x179)+_0x201b7b(0x241)+_0x11a0b6(0x203)+_0x201b7b(0x14f)+_0x201b7b(0x20c)+_0x201b7b(0x234)+_0x11a0b6(0x1e3)+_0x11a0b6(0x1fd)+_0x201b7b(0x1f8)+'ken\x20usage\x20'+_0x11a0b6(0x19e)+_0x201b7b(0x1c3)+'ely,\x20so\x20do'+_0x201b7b(0x231)+'e\x20them.'),_0x521340=_0xd1d580=>{const _0x28c9d5=_0x11a0b6,_0x45a530=_0x11a0b6;switch(_0xd1d580){case _0x28c9d5(0x20e):return['Read',_0x45a530(0x24b),_0x28c9d5(0x182)];case _0x45a530(0x1c2):return[_0x28c9d5(0x17a),'Glob',_0x28c9d5(0x182),_0x28c9d5(0x17e),_0x28c9d5(0x14e)];case'full':default:return undefined;}};for await(const _0x18060c of _0x1d9782[_0x201b7b(0x239)+_0x201b7b(0x21a)]({'prompt':_0xa89cd2[_0x201b7b(0x22e)],'systemPrompt':_0x15a03a,'workingDir':_0x425321,'effort':_0x11a0b6(0x1e0),'abortSignal':_0x543af9[_0x11a0b6(0x172)],'allowedTools':_0x521340(_0xa89cd2[_0x201b7b(0x20b)]??'full')})){_0x18060c[_0x11a0b6(0x1c0)]==='text'&&(_0x18060c['text']&&_0x18060c[_0x11a0b6(0x240)]['length']>0x20ca+-0x16c2+-0x6*0x1ac&&(_0x70f44=_0x18060c[_0x201b7b(0x240)]),_0x3bc9c1&&!_0x3bc9c1[_0x11a0b6(0x180)]&&_0x3bc9c1[_0x201b7b(0x190)](_0x70f44));if(_0x18060c['type']==='done'){if(typeof _0x18060c[_0x11a0b6(0x220)+'t']==='string'&&_0x18060c[_0x11a0b6(0x220)+'t'][_0x11a0b6(0x1ff)]>0xed+-0xaf4*0x1+0x97*0x11)_0x70f44=_0x18060c['finalResul'+'t'];else _0x18060c[_0x201b7b(0x240)]&&_0x18060c[_0x201b7b(0x240)][_0x201b7b(0x1ff)]>-0x781*0x1+-0x810+0xf91&&(_0x70f44=_0x18060c[_0x201b7b(0x240)]);_0x4add52=_0x18060c[_0x11a0b6(0x1f9)+'s']||0x1*-0x2da+0x205d+-0x1d83,_0x3dec8c=_0x18060c['outputToke'+'ns']||0x8b*-0x2b+0x58a+-0x11cf*-0x1;}_0x18060c[_0x11a0b6(0x1c0)]===_0x201b7b(0x18c)&&(_0x5ecd0c=_0x18060c[_0x11a0b6(0x18c)]||_0x201b7b(0x21e)+'or');}if(_0x4bc5d7['result']&&_0x4bc5d7[_0x11a0b6(0x188)][_0x11a0b6(0x1bc)]==='cancelled'){}else{if(_0x543af9['signal'][_0x11a0b6(0x150)])_0x4bc5d7[_0x201b7b(0x188)]={'id':_0x2bd66e,'name':_0x5705d5,'status':'cancelled','output':_0x70f44,'tokensUsed':{'input':_0x4add52,'output':_0x3dec8c},'duration':Date[_0x201b7b(0x15c)]()-_0x18b0df},_0x4bc5d7['info']['status']=_0x11a0b6(0x1cb);else _0x5ecd0c?(_0x4bc5d7[_0x201b7b(0x188)]={'id':_0x2bd66e,'name':_0x5705d5,'status':_0x201b7b(0x18c),'output':_0x70f44,'tokensUsed':{'input':_0x4add52,'output':_0x3dec8c},'duration':Date[_0x11a0b6(0x15c)]()-_0x18b0df,'error':_0x5ecd0c},_0x4bc5d7[_0x201b7b(0x1c6)]['status']=_0x11a0b6(0x18c)):(_0x4bc5d7[_0x201b7b(0x188)]={'id':_0x2bd66e,'name':_0x5705d5,'status':'completed','output':_0x70f44,'tokensUsed':{'input':_0x4add52,'output':_0x3dec8c},'duration':Date[_0x201b7b(0x15c)]()-_0x18b0df},_0x4bc5d7['info']['status']=_0x11a0b6(0x1a4));}if(_0x3bc9c1&&!_0x3bc9c1[_0x201b7b(0x180)]&&_0x4bc5d7[_0x201b7b(0x188)])try{await _0x3bc9c1['finalize'](_0x4bc5d7[_0x201b7b(0x1c6)],_0x4bc5d7[_0x11a0b6(0x188)]),_0x4bc5d7['delivered']=!![];}catch(_0x23fe8d){console['error'](_0x11a0b6(0x156)+_0x2bd66e+(_0x201b7b(0x166)+_0x11a0b6(0x207)+_0x11a0b6(0x169)),_0x23fe8d);}}catch(_0x5fa4f){if(_0x4bc5d7[_0x11a0b6(0x188)]&&_0x4bc5d7[_0x201b7b(0x188)][_0x11a0b6(0x1bc)]===_0x201b7b(0x1cb))return;const _0x1aa65c=_0x5fa4f instanceof Error&&_0x5fa4f[_0x11a0b6(0x164)]['includes'](_0x11a0b6(0x1d9)),_0xbbe028=_0x543af9[_0x201b7b(0x172)][_0x201b7b(0x150)],_0x442226=_0xbbe028?'timeout':_0x1aa65c?'cancelled':_0x201b7b(0x18c);_0x4bc5d7[_0x11a0b6(0x188)]={'id':_0x2bd66e,'name':_0x5705d5,'output':_0x70f44,'tokensUsed':{'input':_0x4add52,'output':_0x3dec8c},'duration':Date[_0x11a0b6(0x15c)]()-_0x18b0df,'error':_0x5fa4f instanceof Error?_0x5fa4f['message']:String(_0x5fa4f),'status':_0x442226},_0x4bc5d7[_0x201b7b(0x1c6)][_0x11a0b6(0x1bc)]=_0x442226;}}const pendingQueue=[],SOURCE_PRIORITY=[_0x1927ee(0x161),'cron',_0x40e016(0x22b)];function sourceOf(_0x5b9f38){const _0x4e9d99=_0x40e016;return _0x5b9f38['source']??_0x4e9d99(0x22b);}function runningCount(){const _0x2d5358=_0x1927ee,_0x2fded3=_0x40e016;return[...activeAgents[_0x2d5358(0x1b5)]()][_0x2fded3(0x15b)](_0x274130=>_0x274130[_0x2fded3(0x1c6)][_0x2d5358(0x1bc)]===_0x2fded3(0x23a))['length'];}function popHighestPriorityQueued(){const _0x4f4b41=_0x40e016,_0x42661f=_0x40e016;for(const _0x35b886 of SOURCE_PRIORITY){const _0x15a0fe=pendingQueue[_0x4f4b41(0x254)](_0xf43af2=>sourceOf(_0xf43af2[_0x4f4b41(0x1b2)+'g'])===_0x35b886);if(_0x15a0fe>=-0xb5*-0xe+-0x11ca+0x7e4){const [_0x38eab5]=pendingQueue[_0x42661f(0x226)](_0x15a0fe,0x1dd0+0x250d*0x1+-0x4*0x10b7);return _0x38eab5;}}return null;}function reindexQueue(){const _0x4266d7=_0x1927ee,_0x276a1b=_0x40e016;for(let _0xe1626f=0x5b*-0x21+-0x4*-0x2a5+0x127;_0xe1626f<pendingQueue[_0x4266d7(0x1ff)];_0xe1626f++){const _0x2ef52a=pendingQueue[_0xe1626f],_0x1f0573=activeAgents[_0x4266d7(0x22a)](_0x2ef52a['id']);if(_0x1f0573)_0x1f0573[_0x276a1b(0x1c6)][_0x4266d7(0x215)+_0x4266d7(0x23e)]=_0xe1626f+(0xc91+-0xdac*-0x1+0x49*-0x5c);}}function drainQueue(){const _0x24eb13=_0x1927ee,_0x4d67b8=_0x40e016,_0x467247=getMaxParallelAgents();while(pendingQueue[_0x24eb13(0x1ff)]>-0x704*0x1+-0x2*-0x1fd+-0x185*-0x2&&runningCount()<_0x467247){const _0xa96896=popHighestPriorityQueued();if(!_0xa96896)break;const _0x4544ec=activeAgents[_0x24eb13(0x22a)](_0xa96896['id']);if(!_0x4544ec)continue;reindexQueue(),_0x4544ec[_0x24eb13(0x1c6)][_0x24eb13(0x1bc)]=_0x24eb13(0x23a),_0x4544ec['info'][_0x4d67b8(0x1e7)]=Date['now'](),_0x4544ec[_0x4d67b8(0x1c6)][_0x24eb13(0x215)+_0x24eb13(0x23e)]=undefined,startRun(_0xa96896);}}function startRun(_0x3d6efd){const _0x2f44a4=_0x1927ee,{id:_0x1151db,resolvedName:_0x5722c9,agentConfig:_0x5d4521,timeoutId:_0x4896d1}=_0x3d6efd,_0x8c4fbc=activeAgents['get'](_0x1151db);if(!_0x8c4fbc)return;runSubAgent(_0x1151db,_0x5d4521,_0x8c4fbc[_0x2f44a4(0x1d9)],_0x5722c9)['finally'](()=>{const _0x57952d=_0x2f44a4,_0x1ac9af=_0x2f44a4;if(_0x4896d1)clearTimeout(_0x4896d1);const _0x73ad6=activeAgents['get'](_0x1151db);if(_0x5d4521[_0x57952d(0x247)]&&_0x73ad6?.[_0x57952d(0x188)])try{_0x5d4521['onComplete'](_0x73ad6[_0x1ac9af(0x188)]);}catch(_0x2b0391){console[_0x1ac9af(0x18c)](_0x57952d(0x156)+_0x1151db+(_0x1ac9af(0x158)+_0x57952d(0x168)+_0x1ac9af(0x22c)),_0x2b0391);}if(_0x73ad6?.[_0x1ac9af(0x188)]&&!_0x73ad6[_0x57952d(0x245)]){_0x73ad6[_0x57952d(0x245)]=!![];const _0x14ac58=_0x73ad6[_0x57952d(0x188)],_0x534753=_0x73ad6[_0x1ac9af(0x1c6)];import(_0x57952d(0x256)+_0x1ac9af(0x1a7)+'js')[_0x57952d(0x18e)](({deliverSubAgentResult:_0x307cfe})=>_0x307cfe(_0x534753,_0x14ac58,{'visibility':_0x5d4521['visibility']}))[_0x57952d(0x1df)](_0x455991=>console['error']('[subagent\x20'+_0x1151db+(_0x57952d(0x1ba)+_0x1ac9af(0x163)),_0x455991));}if(_0x73ad6?.[_0x1ac9af(0x188)]){const _0x210d14=_0x73ad6[_0x57952d(0x188)],_0x174211=_0x73ad6[_0x1ac9af(0x1c6)];import(_0x57952d(0x256)+_0x57952d(0x15a))['then'](({recordSubAgentRun:_0x53bbae})=>_0x53bbae(_0x174211,_0x210d14))[_0x57952d(0x1df)](_0x121b21=>console[_0x57952d(0x18c)](_0x57952d(0x156)+_0x1151db+(']\x20stats\x20re'+_0x1ac9af(0x25e)+_0x57952d(0x1a9)),_0x121b21));}drainQueue(),setTimeout(()=>{const _0x13469d=_0x57952d,_0x2c7d3c=_0x1ac9af,_0x1aa3b3=activeAgents[_0x13469d(0x22a)](_0x1151db);_0x1aa3b3&&_0x1aa3b3[_0x2c7d3c(0x1c6)]['status']!==_0x2c7d3c(0x23a)&&_0x1aa3b3[_0x13469d(0x1c6)]['status']!==_0x13469d(0x230)&&activeAgents['delete'](_0x1151db);},(0x1ef3+0x248b*-0x1+-0x11*-0x56)*(0xa56+0x25a9+-0x1*0x2fc3)*(-0xd72+0x23b7+0x125d*-0x1));});}export function spawnSubAgent(_0x24a3f6){const _0x1d2207=_0x1927ee,_0x3f0ddc=_0x1927ee,_0xf8b38d=_0x24a3f6[_0x1d2207(0x1de)]??-0x1*0x139b+0xc81+-0x12f*-0x6;if(_0xf8b38d>MAX_SUBAGENT_DEPTH)return Promise[_0x1d2207(0x24a)](new Error(_0x1d2207(0x1e2)+_0x3f0ddc(0x1b1)+_0x1d2207(0x153)+'('+MAX_SUBAGENT_DEPTH+(_0x1d2207(0x1ae)+_0x1d2207(0x1dc)+_0x3f0ddc(0x211))+MAX_SUBAGENT_DEPTH+(_0x1d2207(0x24c)+'of\x20nested\x20'+_0x1d2207(0x1a3))));const _0x4cfb0f=_0x24a3f6[_0x3f0ddc(0x20b)]??_0x3f0ddc(0x17d);if(_0x4cfb0f!==_0x1d2207(0x17d)&&_0x4cfb0f!==_0x3f0ddc(0x20e)&&_0x4cfb0f!==_0x3f0ddc(0x1c2))return Promise[_0x1d2207(0x24a)](new Error(_0x1d2207(0x232)+_0x1d2207(0x1a5)+_0x4cfb0f+(_0x3f0ddc(0x17f)+_0x3f0ddc(0x19a)+_0x3f0ddc(0x248)+_0x1d2207(0x208)+_0x1d2207(0x181))));const _0xb422d=getMaxParallelAgents(),_0x108da8=getQueueCap(),_0x8c169=runningCount(),_0x4f3468=pendingQueue[_0x1d2207(0x1ff)],_0x4c967f=resolveAgentName(_0x24a3f6[_0x1d2207(0x1c1)]),_0x446d3e=_0x4c967f['name'],_0x18c5da=_0x154f7a[_0x1d2207(0x175)](),_0x331033=_0x24a3f6[_0x1d2207(0x200)]??getDefaultTimeoutMs(),_0x44da8e=new AbortController(),_0x4389ac=_0x331033>0x6*-0xc5+-0x11d*0x7+0xc69?setTimeout(()=>_0x44da8e['abort'](),_0x331033):null,_0xcd579f=_0x8c169<_0xb422d,_0x138c91=!_0xcd579f&&_0x108da8>-0x1349*0x2+0x1*-0xb15+0x31a7&&_0x4f3468<_0x108da8;if(!_0xcd579f&&!_0x138c91){if(_0x4389ac)clearTimeout(_0x4389ac);const _0x3f753e=sourceOf(_0x24a3f6),_0x4274d8=[...activeAgents[_0x1d2207(0x1b5)]()][_0x3f0ddc(0x15b)](_0x31e601=>_0x31e601[_0x3f0ddc(0x1c6)][_0x1d2207(0x1bc)]===_0x1d2207(0x23a)),_0x3dfd46=_0x4274d8[_0x1d2207(0x15b)](_0x1695da=>_0x1695da[_0x3f0ddc(0x1c6)]['source']===_0x3f0ddc(0x161))['length'],_0x508436=_0x4274d8['length']-_0x3dfd46;let _0x15e974;return _0x3f753e===_0x3f0ddc(0x161)?_0x508436>-0xeab*-0x1+0x1674+0x2b*-0xdd?_0x15e974=_0x1d2207(0x1ce)+_0x1d2207(0x176)+_0x8c169+'/'+_0xb422d+_0x3f0ddc(0x22d)+_0x508436+(_0x3f0ddc(0x1ee)+_0x3f0ddc(0x1ea)+'ntergrund.'+'\x20Queue\x20vol'+_0x1d2207(0x18f))+_0x4f3468+'/'+_0x108da8+(_0x1d2207(0x25a)+_0x3f0ddc(0x16f)+_0x3f0ddc(0x1f4)+_0x3f0ddc(0x1cf)+_0x3f0ddc(0x197)+'cel\x20<name>'+'.'):_0x15e974='Alle\x20Slots'+_0x3f0ddc(0x176)+_0x8c169+'/'+_0xb422d+(_0x3f0ddc(0x1b4)+'nen\x20user-S'+_0x1d2207(0x15e)+_0x3f0ddc(0x216))+_0x4f3468+'/'+_0x108da8+(').\x20/subage'+_0x1d2207(0x1dd)+_0x3f0ddc(0x24e)+_0x3f0ddc(0x1e4)):_0x15e974=_0x3f0ddc(0x1e2)+_0x1d2207(0x185)+'hed\x20('+_0xb422d+_0x1d2207(0x1a8)+_0x4f3468+'/'+_0x108da8+(_0x3f0ddc(0x250)+_0x1d2207(0x235)+_0x3f0ddc(0x14b)+'gent\x20to\x20fi'+_0x1d2207(0x20a)+_0x3f0ddc(0x1d1)),Promise['reject'](new Error(_0x15e974));}const _0x2f377a={'id':_0x18c5da,'name':_0x446d3e,'status':_0xcd579f?_0x1d2207(0x23a):_0x3f0ddc(0x230),'startedAt':Date['now'](),'model':_0x24a3f6[_0x3f0ddc(0x253)],'source':_0x24a3f6[_0x3f0ddc(0x1ef)],'depth':_0xf8b38d,'parentChatId':_0x24a3f6[_0x1d2207(0x233)+'Id'],'nameIndex':_0x4c967f[_0x1d2207(0x184)],'queuePosition':_0xcd579f?undefined:_0x4f3468+(-0x1478+-0x1*0xb43+0x1fbc)};enforceAgentCap(),activeAgents[_0x1d2207(0x1c7)](_0x18c5da,{'info':_0x2f377a,'abort':_0x44da8e,'delivered':![]});const _0x145ddb={'id':_0x18c5da,'resolvedName':_0x446d3e,'agentConfig':_0x24a3f6,'depth':_0xf8b38d,'timeoutId':_0x4389ac};return _0xcd579f?startRun(_0x145ddb):(pendingQueue[_0x3f0ddc(0x229)](_0x145ddb),reindexQueue()),Promise['resolve'](_0x18c5da);}export function listSubAgents(){const _0x5eafbe=_0x1927ee,_0x3df4bd=_0x1927ee;return[...activeAgents[_0x5eafbe(0x1b5)]()][_0x5eafbe(0x162)](_0x1b5da0=>({..._0x1b5da0[_0x3df4bd(0x1c6)]}));}export async function listActiveSubAgents(){const _0x286791=_0x40e016,_0x124ba1=_0x1927ee,_0x29e36e=listSubAgents();let _0x1c1e9b=[];try{const _0x3d8886=await import('./async-ag'+'ent-watche'+_0x286791(0x1d0));if(typeof _0x3d8886[_0x124ba1(0x187)+_0x124ba1(0x25d)]===_0x286791(0x223)){const _0x99c93b=_0x3d8886[_0x124ba1(0x187)+_0x124ba1(0x25d)]();_0x1c1e9b=_0x99c93b['map'](_0x2675c7=>({'id':_0x2675c7[_0x124ba1(0x18d)],'name':_0x2675c7['descriptio'+'n'],'status':'running','startedAt':_0x2675c7[_0x124ba1(0x1e7)],'source':'cron','depth':0x0,'platform':_0x2675c7[_0x124ba1(0x165)],'parentChatId':_0x2675c7[_0x286791(0x20f)]}));}}catch{}return[..._0x29e36e,..._0x1c1e9b];}export function cancelSubAgent(_0xea5b82){const _0x33ad52=_0x40e016,_0x12337c=_0x1927ee,_0x987e73=activeAgents[_0x33ad52(0x22a)](_0xea5b82);if(!_0x987e73)return![];if(_0x987e73[_0x33ad52(0x1c6)][_0x33ad52(0x1bc)]===_0x33ad52(0x230)){const _0x4623d6=pendingQueue[_0x12337c(0x254)](_0x1f7bb4=>_0x1f7bb4['id']===_0xea5b82);if(_0x4623d6>=-0x211e+-0x63*-0x42+-0xc*-0xa2){const [_0x4f3503]=pendingQueue['splice'](_0x4623d6,-0x4ef+0x6d*-0x5+-0x25b*-0x3);if(_0x4f3503[_0x12337c(0x18b)])clearTimeout(_0x4f3503['timeoutId']);reindexQueue();}return _0x987e73[_0x33ad52(0x1c6)][_0x33ad52(0x1bc)]=_0x12337c(0x1cb),!![];}if(_0x987e73['info']['status']!=='running')return![];return _0x987e73['abort'][_0x12337c(0x1d9)](),_0x987e73[_0x33ad52(0x1c6)][_0x12337c(0x1bc)]='cancelled',!![];}export function getSubAgentResult(_0x566197){const _0x3c3f02=_0x40e016,_0x43d7c4=_0x1927ee,_0x1eed61=activeAgents[_0x3c3f02(0x22a)](_0x566197);return _0x1eed61?.[_0x3c3f02(0x188)]??null;}export function cancelSubAgentByName(_0x2fd157){const _0x1cb916=_0x1927ee,_0x40243b=findSubAgentByName(_0x2fd157);if(!_0x40243b||_0x1cb916(0x19b)in _0x40243b)return![];return cancelSubAgent(_0x40243b['id']);}export function getSubAgentResultByName(_0x19737b){const _0x55b12a=_0x1927ee,_0x4b642a=findSubAgentByName(_0x19737b);if(!_0x4b642a||_0x55b12a(0x19b)in _0x4b642a)return null;return getSubAgentResult(_0x4b642a['id']);}export async function cancelAllSubAgents(_0x19fdde=!![]){const _0x25ad68=_0x1927ee,_0x448d71=_0x40e016,_0x4d6065=[],_0x1ae730=[];for(const _0xe932f1 of pendingQueue['splice'](-0x2*0x29+0xef9+-0xea7)){if(_0xe932f1[_0x25ad68(0x18b)])clearTimeout(_0xe932f1['timeoutId']);const _0x293fdf=activeAgents['get'](_0xe932f1['id']);_0x293fdf&&(_0x293fdf[_0x25ad68(0x1c6)][_0x448d71(0x1bc)]=_0x448d71(0x1cb),_0x293fdf[_0x448d71(0x245)]=!![]);}for(const [_0x4a79a7,_0x715495]of activeAgents){if(_0x715495[_0x25ad68(0x1c6)][_0x25ad68(0x1bc)]!=='running')continue;_0x715495[_0x25ad68(0x1d9)][_0x448d71(0x1d9)](),_0x715495[_0x25ad68(0x1c6)][_0x448d71(0x1bc)]=_0x448d71(0x1cb);const _0x46182e={'id':_0x4a79a7,'name':_0x715495['info']['name'],'status':_0x448d71(0x1cb),'output':_0x448d71(0x178)+_0x448d71(0x1e5)+_0x448d71(0x16a)+_0x25ad68(0x16c)+_0x448d71(0x238)+_0x25ad68(0x20d)+_0x448d71(0x259),'tokensUsed':{'input':0x0,'output':0x0},'duration':Date[_0x448d71(0x15c)]()-_0x715495['info'][_0x448d71(0x1e7)]};_0x715495[_0x25ad68(0x188)]=_0x46182e,_0x715495['delivered']=!![],_0x1ae730['push']({'id':_0x4a79a7,'info':_0x715495[_0x448d71(0x1c6)],'cancelResult':_0x46182e});}if(!_0x19fdde||_0x1ae730['length']===-0x209*0x12+-0x5*0x199+-0x2c9f*-0x1)return;const {deliverSubAgentResult:_0x222050}=await import(_0x448d71(0x256)+_0x25ad68(0x1a7)+'js');for(const {id:_0x503f68,info:_0xfe2c27,cancelResult:_0x135edf}of _0x1ae730){const _0x14fcf1=Promise['resolve'](_0x222050(_0xfe2c27,_0x135edf))[_0x448d71(0x1df)](_0x18d185=>{const _0x5eb807=_0x25ad68,_0x136c8f=_0x25ad68;console[_0x5eb807(0x18c)](_0x5eb807(0x194)+']\x20shutdown'+_0x136c8f(0x1e8)+_0x136c8f(0x1af)+_0x503f68+':',_0x18d185);});_0x4d6065[_0x25ad68(0x229)](_0x14fcf1);}await Promise['race']([Promise[_0x448d71(0x246)](_0x4d6065),new Promise(_0x4faecc=>setTimeout(_0x4faecc,0x1928+-0x1f4f+0x19af))]);}
|