@songsid/agend 2.1.0-beta.27 → 2.1.0-beta.29
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/classic-channel-manager.d.ts +4 -0
- package/dist/classic-channel-manager.js +15 -0
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +15 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +12 -0
- package/dist/daemon.js +40 -20
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +21 -2
- package/dist/fleet-manager.js +132 -10
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +1 -0
- package/dist/instance-lifecycle.js +27 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/pause-marker.d.ts +5 -0
- package/dist/pause-marker.js +36 -0
- package/dist/pause-marker.js.map +1 -0
- package/dist/settings-api.d.ts +1 -0
- package/dist/settings-api.js +12 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/ui/settings.html +98 -21
- package/package.json +1 -1
package/dist/fleet-manager.js
CHANGED
|
@@ -41,6 +41,7 @@ import { setLocale, detectLocale, t } from "./locale.js";
|
|
|
41
41
|
import { handleAgentRequest } from "./agent-endpoint.js";
|
|
42
42
|
import { ClassicChannelManager, getClassicBackendChoices, isSelectableClassicBackend, readClassicLastActivityAt } from "./classic-channel-manager.js";
|
|
43
43
|
import { readLastInboundAt } from "./daemon.js";
|
|
44
|
+
import { clearPausedMarker } from "./pause-marker.js";
|
|
44
45
|
import { getTmuxSession } from "./config.js";
|
|
45
46
|
export function resolveReplyThreadId(argsThreadId, instanceConfig) {
|
|
46
47
|
if (typeof argsThreadId === "string" && argsThreadId.length > 0) {
|
|
@@ -101,6 +102,12 @@ export class FleetManager {
|
|
|
101
102
|
lastActivity = new Map();
|
|
102
103
|
/** Latest pane-derived execution snapshot reported by each daemon. */
|
|
103
104
|
instanceStateCache = new Map();
|
|
105
|
+
/** Per-instance tail keeps cross-instance and scheduled deliveries FIFO. */
|
|
106
|
+
idleGatedDeliveryTails = new Map();
|
|
107
|
+
/** Non-user work must observe a fresh idle snapshot after the latest delivery. */
|
|
108
|
+
lastDeliveryAt = new Map();
|
|
109
|
+
/** State-cache updates wake event-driven idle waiters without busy polling. */
|
|
110
|
+
instanceIdleWaiters = new Map();
|
|
104
111
|
lastInboundUser = new Map(); // instanceName → last username
|
|
105
112
|
// Active "🛑 Cancel" buttons, tracked per button (keyed by messageId) rather
|
|
106
113
|
// than one-per-instance. A button is retired (deleted, with bounded retry) on
|
|
@@ -357,6 +364,9 @@ export class FleetManager {
|
|
|
357
364
|
return null;
|
|
358
365
|
return this.instanceStateCache.get(name)?.state ?? null;
|
|
359
366
|
}
|
|
367
|
+
isClassicInstance(name) {
|
|
368
|
+
return this.classicChannels?.getAll().some(channel => channel.instanceName === name) ?? false;
|
|
369
|
+
}
|
|
360
370
|
cacheInstanceExecutionState(name, msg) {
|
|
361
371
|
const state = msg.state;
|
|
362
372
|
if (state !== "idle" && state !== "working" && state !== "stuck")
|
|
@@ -370,16 +380,100 @@ export class FleetManager {
|
|
|
370
380
|
observedAt: numberOr(msg.observedAt, now),
|
|
371
381
|
stateChangedAt: numberOr(msg.stateChangedAt, previous?.state === state ? previous.stateChangedAt : now),
|
|
372
382
|
});
|
|
383
|
+
for (const check of this.instanceIdleWaiters.get(name) ?? [])
|
|
384
|
+
check();
|
|
385
|
+
}
|
|
386
|
+
waitForInstanceIdle(instanceName, timeoutMs, idleObservedAfter = 0) {
|
|
387
|
+
const isReady = () => {
|
|
388
|
+
const snapshot = this.instanceStateCache.get(instanceName);
|
|
389
|
+
return snapshot?.state === "idle"
|
|
390
|
+
&& (idleObservedAfter === 0 || snapshot.observedAt > idleObservedAfter);
|
|
391
|
+
};
|
|
392
|
+
if (isReady())
|
|
393
|
+
return Promise.resolve(true);
|
|
394
|
+
return new Promise(resolve => {
|
|
395
|
+
let settled = false;
|
|
396
|
+
const finish = (idle) => {
|
|
397
|
+
if (settled)
|
|
398
|
+
return;
|
|
399
|
+
settled = true;
|
|
400
|
+
clearTimeout(timeout);
|
|
401
|
+
clearInterval(queryTimer);
|
|
402
|
+
const waiters = this.instanceIdleWaiters.get(instanceName);
|
|
403
|
+
waiters?.delete(check);
|
|
404
|
+
if (waiters?.size === 0)
|
|
405
|
+
this.instanceIdleWaiters.delete(instanceName);
|
|
406
|
+
resolve(idle);
|
|
407
|
+
};
|
|
408
|
+
const check = () => { if (isReady())
|
|
409
|
+
finish(true); };
|
|
410
|
+
const query = () => {
|
|
411
|
+
const ipc = this.instanceIpcClients.get(instanceName);
|
|
412
|
+
if (ipc?.connected) {
|
|
413
|
+
ipc.send({ type: "query_instance_state", requestId: `idle-gate-${Date.now()}` });
|
|
414
|
+
}
|
|
415
|
+
check();
|
|
416
|
+
};
|
|
417
|
+
const waiters = this.instanceIdleWaiters.get(instanceName) ?? new Set();
|
|
418
|
+
waiters.add(check);
|
|
419
|
+
this.instanceIdleWaiters.set(instanceName, waiters);
|
|
420
|
+
const timeout = setTimeout(() => finish(false), timeoutMs);
|
|
421
|
+
const queryTimer = setInterval(query, 1_000);
|
|
422
|
+
query();
|
|
423
|
+
});
|
|
373
424
|
}
|
|
374
|
-
|
|
375
|
-
|
|
425
|
+
async deliverWithIdleGate(instanceName, payload, timeoutMs) {
|
|
426
|
+
let idleObservedAfter = this.lastDeliveryAt.get(instanceName) ?? 0;
|
|
376
427
|
if (this.lifecycle.isPaused(instanceName)) {
|
|
428
|
+
const wakeStartedAt = Date.now();
|
|
377
429
|
await this.lifecycle.wake(instanceName, 30_000);
|
|
430
|
+
// Never satisfy a post-wake gate from a stale pre-pause cache entry.
|
|
431
|
+
idleObservedAfter = Math.max(idleObservedAfter, wakeStartedAt);
|
|
432
|
+
}
|
|
433
|
+
const idle = await this.waitForInstanceIdle(instanceName, timeoutMs, idleObservedAfter);
|
|
434
|
+
if (!idle) {
|
|
435
|
+
this.logger.warn({ instanceName, timeoutMs }, "Idle gate timed out; forcing delivery");
|
|
378
436
|
}
|
|
379
437
|
const ipc = this.instanceIpcClients.get(instanceName);
|
|
380
438
|
if (!ipc?.connected)
|
|
381
439
|
throw new Error(`Instance '${instanceName}' IPC is unavailable`);
|
|
382
440
|
ipc.send(payload);
|
|
441
|
+
this.lastDeliveryAt.set(instanceName, Date.now());
|
|
442
|
+
}
|
|
443
|
+
/** Single delivery facade: wake paused CLIs and serialize non-user work behind idle. */
|
|
444
|
+
async deliverToInstance(instanceName, payload, options = {}) {
|
|
445
|
+
const meta = payload.meta && typeof payload.meta === "object"
|
|
446
|
+
? payload.meta
|
|
447
|
+
: undefined;
|
|
448
|
+
const inferredCrossInstance = (typeof meta?.from_instance === "string" && meta.from_instance.length > 0)
|
|
449
|
+
|| meta?.is_cross_instance === true
|
|
450
|
+
|| payload.is_cross_instance === true;
|
|
451
|
+
const waitForIdle = options.waitForIdle
|
|
452
|
+
?? ((options.isCrossInstance ?? inferredCrossInstance) || payload.type === "fleet_schedule_trigger");
|
|
453
|
+
if (!waitForIdle) {
|
|
454
|
+
if (this.lifecycle.isPaused(instanceName)) {
|
|
455
|
+
await this.lifecycle.wake(instanceName, 30_000);
|
|
456
|
+
}
|
|
457
|
+
const ipc = this.instanceIpcClients.get(instanceName);
|
|
458
|
+
if (!ipc?.connected)
|
|
459
|
+
throw new Error(`Instance '${instanceName}' IPC is unavailable`);
|
|
460
|
+
ipc.send(payload);
|
|
461
|
+
// A cross-instance item arriving before the daemon observes this turn as
|
|
462
|
+
// working must not trust the stale idle snapshot from before the send.
|
|
463
|
+
this.lastDeliveryAt.set(instanceName, Date.now());
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
const previous = this.idleGatedDeliveryTails.get(instanceName) ?? Promise.resolve();
|
|
467
|
+
const delivery = previous.catch(() => { }).then(() => this.deliverWithIdleGate(instanceName, payload, options.idleTimeoutMs ?? 60_000));
|
|
468
|
+
this.idleGatedDeliveryTails.set(instanceName, delivery);
|
|
469
|
+
try {
|
|
470
|
+
await delivery;
|
|
471
|
+
}
|
|
472
|
+
finally {
|
|
473
|
+
if (this.idleGatedDeliveryTails.get(instanceName) === delivery) {
|
|
474
|
+
this.idleGatedDeliveryTails.delete(instanceName);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
383
477
|
}
|
|
384
478
|
/** Fleet admin is an explicit config allowlist entry, not merely an open/paired user. */
|
|
385
479
|
isFleetAdmin(userId, adapterId) {
|
|
@@ -408,9 +502,13 @@ export class FleetManager {
|
|
|
408
502
|
return;
|
|
409
503
|
await this.stopInstance(instanceName);
|
|
410
504
|
await new Promise(resolve => setTimeout(resolve, 250));
|
|
411
|
-
await this.startClassicInstance(instanceName, this.classicChannels.getBackendByInstance(instanceName, this.fleetConfig?.defaults?.backend), this.classicChannels.getPreTaskCommand(channel.channelId, channel.adapterId), this.classicChannels.getModel(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.model));
|
|
505
|
+
await this.startClassicInstance(instanceName, this.classicChannels.getBackendByInstance(instanceName, this.fleetConfig?.defaults?.backend), this.classicChannels.getPreTaskCommand(channel.channelId, channel.adapterId), this.classicChannels.getModel(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.model), this.classicChannels.getAutoPauseAfter(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.auto_pause_after));
|
|
412
506
|
}
|
|
413
507
|
async startInstance(name, config, topicMode) {
|
|
508
|
+
if (this.lifecycle.isPaused(name)) {
|
|
509
|
+
this.logger.info({ name }, "Persisted paused instance — skipping startup");
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
414
512
|
if (config.general_topic) {
|
|
415
513
|
this.ensureGeneralInstructions(config.working_directory, config.backend);
|
|
416
514
|
}
|
|
@@ -418,6 +516,20 @@ export class FleetManager {
|
|
|
418
516
|
// Auto-connect IPC — daemon.start() ensures socket is ready before resolving
|
|
419
517
|
await this.connectIpcToInstance(name);
|
|
420
518
|
}
|
|
519
|
+
/** Recreate a daemon for a marker-only paused instance after an explicit wake/delivery. */
|
|
520
|
+
async startPersistedPausedInstance(name) {
|
|
521
|
+
const topicMode = this.fleetConfig?.channel?.mode === "topic"
|
|
522
|
+
|| !!this.fleetConfig?.channels?.some(channel => channel.mode === "topic");
|
|
523
|
+
const fleetConfig = this.fleetConfig?.instances[name];
|
|
524
|
+
if (fleetConfig) {
|
|
525
|
+
await this.startInstance(name, fleetConfig, topicMode);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const channel = this.classicChannels?.getAll().find(item => item.instanceName === name);
|
|
529
|
+
if (!channel || !this.classicChannels)
|
|
530
|
+
throw new Error(`Paused instance '${name}' is no longer configured`);
|
|
531
|
+
await this.startClassicInstance(name, this.classicChannels.getBackendByInstance(name, this.fleetConfig?.defaults?.backend), this.classicChannels.getPreTaskCommand(channel.channelId, channel.adapterId), this.classicChannels.getModel(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.model), this.classicChannels.getAutoPauseAfter(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.auto_pause_after));
|
|
532
|
+
}
|
|
421
533
|
/**
|
|
422
534
|
* Start instances with configurable concurrency and stagger delay.
|
|
423
535
|
* Instances sharing the same working_directory are serialized within a group
|
|
@@ -478,6 +590,7 @@ export class FleetManager {
|
|
|
478
590
|
async stopInstance(name) {
|
|
479
591
|
this.failoverActive.delete(name);
|
|
480
592
|
this.instanceStateCache.delete(name);
|
|
593
|
+
this.lastDeliveryAt.delete(name);
|
|
481
594
|
return this.lifecycle.stop(name);
|
|
482
595
|
}
|
|
483
596
|
/** Restart a single instance, reloading fleet.yaml first to pick up config changes. */
|
|
@@ -588,9 +701,11 @@ export class FleetManager {
|
|
|
588
701
|
const fleetModel = this.fleetConfig?.defaults?.model;
|
|
589
702
|
const oldBackends = new Map();
|
|
590
703
|
const oldModels = new Map();
|
|
704
|
+
const oldAutoPause = new Map();
|
|
591
705
|
for (const ch of this.classicChannels.getAll()) {
|
|
592
706
|
oldBackends.set(ch.instanceName, this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend));
|
|
593
707
|
oldModels.set(ch.instanceName, this.classicChannels.getModel(ch.channelId, ch.adapterId, fleetModel));
|
|
708
|
+
oldAutoPause.set(ch.instanceName, this.classicChannels.getAutoPauseAfter(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.auto_pause_after));
|
|
594
709
|
}
|
|
595
710
|
if (!this.classicChannels.checkReload())
|
|
596
711
|
return;
|
|
@@ -598,14 +713,16 @@ export class FleetManager {
|
|
|
598
713
|
for (const ch of this.classicChannels.getAll()) {
|
|
599
714
|
const newBackend = this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend);
|
|
600
715
|
const newModel = this.classicChannels.getModel(ch.channelId, ch.adapterId, fleetModel);
|
|
716
|
+
const newAutoPause = this.classicChannels.getAutoPauseAfter(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.auto_pause_after);
|
|
601
717
|
const backendChanged = oldBackends.get(ch.instanceName) !== newBackend;
|
|
602
718
|
const modelChanged = oldModels.get(ch.instanceName) !== newModel;
|
|
603
|
-
|
|
719
|
+
const autoPauseChanged = oldAutoPause.get(ch.instanceName) !== newAutoPause;
|
|
720
|
+
if (this.daemons.has(ch.instanceName) && (backendChanged || modelChanged || autoPauseChanged)) {
|
|
604
721
|
this.logger.info({ instanceName: ch.instanceName, backendFrom: oldBackends.get(ch.instanceName), backendTo: newBackend, modelFrom: oldModels.get(ch.instanceName), modelTo: newModel }, "Backend/model changed — restarting");
|
|
605
722
|
await this.stopInstance(ch.instanceName).catch(() => { });
|
|
606
723
|
// Small delay to let tmux window clean up
|
|
607
724
|
await new Promise(r => setTimeout(r, 2000));
|
|
608
|
-
await this.startClassicInstance(ch.instanceName, newBackend, this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), newModel).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to restart classic instance"));
|
|
725
|
+
await this.startClassicInstance(ch.instanceName, newBackend, this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), newModel, newAutoPause).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to restart classic instance"));
|
|
609
726
|
}
|
|
610
727
|
}
|
|
611
728
|
}
|
|
@@ -858,7 +975,7 @@ export class FleetManager {
|
|
|
858
975
|
let idx = 0;
|
|
859
976
|
while (idx < channels.length) {
|
|
860
977
|
const batch = channels.slice(idx, idx + concurrency);
|
|
861
|
-
await Promise.allSettled(batch.map(ch => this.startClassicInstance(ch.instanceName, this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend), this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), this.classicChannels.getModel(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.model)).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to start classic instance"))));
|
|
978
|
+
await Promise.allSettled(batch.map(ch => this.startClassicInstance(ch.instanceName, this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend), this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), this.classicChannels.getModel(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.model), this.classicChannels.getAutoPauseAfter(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.auto_pause_after)).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to start classic instance"))));
|
|
862
979
|
idx += concurrency;
|
|
863
980
|
}
|
|
864
981
|
}
|
|
@@ -2375,7 +2492,7 @@ export class FleetManager {
|
|
|
2375
2492
|
type: "fleet_schedule_trigger",
|
|
2376
2493
|
payload: { schedule_id: id, message: `[Scheduled] ${message}`, label },
|
|
2377
2494
|
meta: { chat_id: reply_chat_id, thread_id: reply_thread_id, user: "scheduler" },
|
|
2378
|
-
});
|
|
2495
|
+
}, { waitForIdle: true });
|
|
2379
2496
|
// A scheduled trigger also puts the instance to work — show a cancel button.
|
|
2380
2497
|
void this.sendCancelButton(target);
|
|
2381
2498
|
return true;
|
|
@@ -2943,6 +3060,8 @@ export class FleetManager {
|
|
|
2943
3060
|
}
|
|
2944
3061
|
}
|
|
2945
3062
|
startStatuslineWatcher(name) {
|
|
3063
|
+
if (this.lifecycle.isPaused(name))
|
|
3064
|
+
return;
|
|
2946
3065
|
this.statuslineWatcher.watch(name);
|
|
2947
3066
|
}
|
|
2948
3067
|
stopStatuslineWatcher(name) {
|
|
@@ -4019,7 +4138,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4019
4138
|
await pending.complete(warning ? `${warning}\n\n${reply}` : reply, pending.messageId);
|
|
4020
4139
|
}
|
|
4021
4140
|
/** Start a classic channel instance with lightweight config */
|
|
4022
|
-
async startClassicInstance(instanceName, backend, preTaskCommand, model) {
|
|
4141
|
+
async startClassicInstance(instanceName, backend, preTaskCommand, model, autoPauseAfter) {
|
|
4023
4142
|
if (this.daemons.has(instanceName))
|
|
4024
4143
|
return;
|
|
4025
4144
|
const workDir = join(getAgendHome(), "workspaces", instanceName);
|
|
@@ -4031,6 +4150,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4031
4150
|
lightweight: true,
|
|
4032
4151
|
...(backend ? { backend } : {}),
|
|
4033
4152
|
...(model ? { model } : {}),
|
|
4153
|
+
...(autoPauseAfter !== undefined ? { auto_pause_after: autoPauseAfter } : {}),
|
|
4034
4154
|
...(preTaskCommand ? { pre_task_command: preTaskCommand } : {}),
|
|
4035
4155
|
};
|
|
4036
4156
|
const topicMode = this.fleetConfig?.channel?.mode === "topic";
|
|
@@ -4045,6 +4165,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4045
4165
|
if (!classicChannels)
|
|
4046
4166
|
return "Classic channel manager not initialized.";
|
|
4047
4167
|
const instanceName = classicChannels.deriveInstanceName(channelName || channelId, channelId, adapterId);
|
|
4168
|
+
clearPausedMarker(this.getInstanceDir(instanceName));
|
|
4048
4169
|
const selectedBackend = isSelectableClassicBackend(backend) ? backend : undefined;
|
|
4049
4170
|
classicChannels.register(channelId, adapterId, instanceName, channelName || channelId, userId, selectedBackend);
|
|
4050
4171
|
// Bind this classic instance to the bot that started it (authoritative), so
|
|
@@ -4052,7 +4173,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4052
4173
|
// also sees the channel's messages.
|
|
4053
4174
|
if (adapterId)
|
|
4054
4175
|
this.bindInstanceAdapter(instanceName, adapterId);
|
|
4055
|
-
await this.startClassicInstance(instanceName, classicChannels.getBackend(channelId, adapterId, this.fleetConfig?.defaults?.backend), classicChannels.getPreTaskCommand(channelId, adapterId), classicChannels.getModel(channelId, adapterId, this.fleetConfig?.defaults?.model));
|
|
4176
|
+
await this.startClassicInstance(instanceName, classicChannels.getBackend(channelId, adapterId, this.fleetConfig?.defaults?.backend), classicChannels.getPreTaskCommand(channelId, adapterId), classicChannels.getModel(channelId, adapterId, this.fleetConfig?.defaults?.model), classicChannels.getAutoPauseAfter(channelId, adapterId, this.fleetConfig?.defaults?.auto_pause_after));
|
|
4056
4177
|
this.reregisterClassicChannels();
|
|
4057
4178
|
// Auto-enable collab for Discord classic channels (TG uses @mention directly without collab mode)
|
|
4058
4179
|
if (guildId && !classicChannels.isCollab(channelId, adapterId)) {
|
|
@@ -4070,6 +4191,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4070
4191
|
return t("classic.no_agent");
|
|
4071
4192
|
this.instanceWorldBinding.delete(ch.instanceName);
|
|
4072
4193
|
await this.stopInstance(ch.instanceName).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to stop classic instance"));
|
|
4194
|
+
clearPausedMarker(this.getInstanceDir(ch.instanceName));
|
|
4073
4195
|
this.reregisterClassicChannels();
|
|
4074
4196
|
this.logger.info({ channelId, adapterId, instanceName: ch.instanceName }, "Classic channel stopped");
|
|
4075
4197
|
return t("classic.stopped");
|
|
@@ -4410,7 +4532,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4410
4532
|
let idx = 0;
|
|
4411
4533
|
while (idx < channels.length) {
|
|
4412
4534
|
const batch = channels.slice(idx, idx + concurrency);
|
|
4413
|
-
await Promise.allSettled(batch.map(ch => this.startClassicInstance(ch.instanceName, this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend), this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), this.classicChannels.getModel(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.model)).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to start classic instance"))));
|
|
4535
|
+
await Promise.allSettled(batch.map(ch => this.startClassicInstance(ch.instanceName, this.classicChannels.getBackendByInstance(ch.instanceName, fleetBackend), this.classicChannels.getPreTaskCommand(ch.channelId, ch.adapterId), this.classicChannels.getModel(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.model), this.classicChannels.getAutoPauseAfter(ch.channelId, ch.adapterId, this.fleetConfig?.defaults?.auto_pause_after)).catch(err => this.logger.warn({ err, instanceName: ch.instanceName }, "Failed to start classic instance"))));
|
|
4414
4536
|
idx += concurrency;
|
|
4415
4537
|
}
|
|
4416
4538
|
}
|