@songsid/agend 2.1.2-beta.24 β 2.1.2-beta.25
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/channel/adapters/discord.js +5 -8
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +5 -1
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +4 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/config-validator.js +6 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/fleet-context.d.ts +5 -0
- package/dist/fleet-manager.d.ts +13 -1
- package/dist/fleet-manager.js +70 -16
- package/dist/fleet-manager.js.map +1 -1
- package/dist/outbound-handlers.js +31 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +3 -0
- package/dist/outbound-schemas.js +3 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/topic-commands.js +6 -3
- package/dist/topic-commands.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/usage/format-rich.js +8 -0
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/usage-api.js +61 -5
- package/dist/usage/usage-api.js.map +1 -1
- package/package.json +1 -1
package/dist/fleet-manager.js
CHANGED
|
@@ -122,19 +122,24 @@ const CANCEL_BTN_LEDGER_FILE = "cancel-buttons.json";
|
|
|
122
122
|
*/
|
|
123
123
|
const PROGRESS_UPDATE_INTERVAL_MS = 60_000;
|
|
124
124
|
/** Elapsed time is only shown once work has clearly outlasted a quick answer. */
|
|
125
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Default delay before the button starts showing elapsed time. Configurable via
|
|
127
|
+
* `defaults.progress_min_elapsed` (seconds) in fleet.yaml. 30s is the balance
|
|
128
|
+
* point: most quick answers finish inside it (no churn for ordinary turns),
|
|
129
|
+
* while anything real shows signs of life well before the old two minutes.
|
|
130
|
+
*/
|
|
131
|
+
const PROGRESS_MIN_ELAPSED_MS = 30_000;
|
|
126
132
|
/** How much of a tool summary the progress line will show before eliding. */
|
|
127
133
|
const PROGRESS_ACTIVITY_MAX_CHARS = 48;
|
|
128
134
|
/**
|
|
129
|
-
* Emoji AgEnD itself stamps on messages as
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* already attached to these glyphs, that reading is ambiguous anyway.
|
|
135
|
+
* Emoji AgEnD itself stamps on messages as the delivery-status ladder
|
|
136
|
+
* (β³ queued, π delivered, β
confirmed, β failed). These are machine
|
|
137
|
+
* indicators, not opinions, so they never enter the reactions queue β from
|
|
138
|
+
* anyone. This exact-emoji filter is the ONLY bot filtering left: bot-to-bot
|
|
139
|
+
* reactions are otherwise delivered on purpose (agents signal each other), and
|
|
140
|
+
* π«‘ passes too β it reads as a deliberate acknowledgement, not plumbing.
|
|
136
141
|
*/
|
|
137
|
-
const DELIVERY_STATUS_EMOJIS = new Set(["π", "β³", "β
", "β"
|
|
142
|
+
const DELIVERY_STATUS_EMOJIS = new Set(["π", "β³", "β
", "β"]);
|
|
138
143
|
/**
|
|
139
144
|
* How long a delivery waits out a disconnected instance IPC before giving up.
|
|
140
145
|
*
|
|
@@ -4226,8 +4231,8 @@ export class FleetManager {
|
|
|
4226
4231
|
* progress indicator (#409) β the channel showed nothing at all during long work,
|
|
4227
4232
|
* and once the agent had replied once there was no sign it was still going.
|
|
4228
4233
|
*/
|
|
4229
|
-
static progressText(elapsedMs, activity) {
|
|
4230
|
-
if (elapsedMs <
|
|
4234
|
+
static progressText(elapsedMs, activity, minElapsedMs = PROGRESS_MIN_ELAPSED_MS) {
|
|
4235
|
+
if (elapsedMs < minElapsedMs)
|
|
4231
4236
|
return "π θηδΈβ¦";
|
|
4232
4237
|
const totalSeconds = Math.floor(elapsedMs / 1000);
|
|
4233
4238
|
const minutes = Math.floor(totalSeconds / 60);
|
|
@@ -4278,13 +4283,22 @@ export class FleetManager {
|
|
|
4278
4283
|
* and the Bot API treats that as "clear the keyboard" β so editing with it would
|
|
4279
4284
|
* delete the very cancel button this is trying to keep alive.
|
|
4280
4285
|
*/
|
|
4286
|
+
/** Configured threshold before elapsed time appears, in ms. */
|
|
4287
|
+
progressMinElapsedMs() {
|
|
4288
|
+
const seconds = this.fleetConfig?.defaults
|
|
4289
|
+
?.progress_min_elapsed;
|
|
4290
|
+
if (typeof seconds === "number" && Number.isFinite(seconds) && seconds >= 0) {
|
|
4291
|
+
return seconds * 1000;
|
|
4292
|
+
}
|
|
4293
|
+
return PROGRESS_MIN_ELAPSED_MS;
|
|
4294
|
+
}
|
|
4281
4295
|
startProgressTicker(entry) {
|
|
4282
|
-
|
|
4296
|
+
const tick = () => {
|
|
4283
4297
|
if (!this.cancelButtons.has(entry.messageId)) {
|
|
4284
4298
|
clearInterval(entry.progressTimer);
|
|
4285
4299
|
return;
|
|
4286
4300
|
}
|
|
4287
|
-
const text = FleetManager.progressText(Date.now() - (entry.startedAt ?? Date.now()), this.instanceActivity.get(entry.instanceName));
|
|
4301
|
+
const text = FleetManager.progressText(Date.now() - (entry.startedAt ?? Date.now()), this.instanceActivity.get(entry.instanceName), this.progressMinElapsedMs());
|
|
4288
4302
|
if (text === entry.lastProgressText)
|
|
4289
4303
|
return; // nothing changed β skip the API call
|
|
4290
4304
|
const adapter = this.getAdapterForInstance(entry.instanceName) ?? this.adapter;
|
|
@@ -4303,8 +4317,17 @@ export class FleetManager {
|
|
|
4303
4317
|
// rate limit.
|
|
4304
4318
|
this.logger.debug({ err, instanceName: entry.instanceName }, "Progress edit failed");
|
|
4305
4319
|
});
|
|
4306
|
-
}
|
|
4320
|
+
};
|
|
4321
|
+
entry.progressTimer = setInterval(tick, PROGRESS_UPDATE_INTERVAL_MS);
|
|
4307
4322
|
entry.progressTimer.unref?.();
|
|
4323
|
+
// One extra tick right when the threshold passes, so a 30s threshold shows
|
|
4324
|
+
// time at ~30s instead of waiting for the first 60s interval. Costs at most
|
|
4325
|
+
// one additional edit per turn that lives past the threshold.
|
|
4326
|
+
const firstAt = this.progressMinElapsedMs() - (Date.now() - (entry.startedAt ?? Date.now()));
|
|
4327
|
+
if (firstAt > 0 && firstAt < PROGRESS_UPDATE_INTERVAL_MS) {
|
|
4328
|
+
const firstTick = setTimeout(tick, firstAt);
|
|
4329
|
+
firstTick.unref?.();
|
|
4330
|
+
}
|
|
4308
4331
|
}
|
|
4309
4332
|
/**
|
|
4310
4333
|
* After a reply: give the instance REPLY_RETIRE_GRACE_MS to resume working; if
|
|
@@ -5572,6 +5595,20 @@ When users create specialized instances, suggest these configurations:
|
|
|
5572
5595
|
/** Apply a model to an instance: runtime paste (claude-code) or persist + restart (others). */
|
|
5573
5596
|
/** AgEnD's canonical effort ladder, low β max. Backends expose a subset. */
|
|
5574
5597
|
static EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
5598
|
+
/** How this instance's backend applies an effort change. */
|
|
5599
|
+
effortStrategyFor(instanceName) {
|
|
5600
|
+
try {
|
|
5601
|
+
const backend = createBackend(this.backendNameForInstance(instanceName), this.getInstanceDir(instanceName));
|
|
5602
|
+
const strategy = backend.getEffortStrategy?.() ?? "unsupported";
|
|
5603
|
+
// A backend claiming support but listing no levels is unusable either way.
|
|
5604
|
+
return strategy !== "unsupported" && (backend.getEffortLevels?.() ?? []).length > 0
|
|
5605
|
+
? strategy
|
|
5606
|
+
: "unsupported";
|
|
5607
|
+
}
|
|
5608
|
+
catch {
|
|
5609
|
+
return "unsupported";
|
|
5610
|
+
}
|
|
5611
|
+
}
|
|
5575
5612
|
/** Effort levels this instance's backend actually accepts (empty = unsupported). */
|
|
5576
5613
|
effortLevelsFor(instanceName) {
|
|
5577
5614
|
try {
|
|
@@ -5672,7 +5709,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
5672
5709
|
if (!this.instanceIpcClients.get(instanceName))
|
|
5673
5710
|
return `${warn}β ${instanceName} is not running.`;
|
|
5674
5711
|
this.pasteRawToClassicInstance(instanceName, `/model ${model}`);
|
|
5675
|
-
return `${warn}β
Switched ${instanceName} to \`${model}\` (runtime)
|
|
5712
|
+
return `${warn}β
Switched ${instanceName} to \`${model}\` (runtime).${this.effortSuffix(instanceName)}`;
|
|
5676
5713
|
}
|
|
5677
5714
|
// restart: persist the model so the respawned CLI launches with it.
|
|
5678
5715
|
let persisted = false;
|
|
@@ -5687,7 +5724,24 @@ When users create specialized instances, suggest these configurations:
|
|
|
5687
5724
|
if (!persisted)
|
|
5688
5725
|
return `${warn}β Could not set model for ${instanceName}.`;
|
|
5689
5726
|
await this.restartSingleInstance(instanceName);
|
|
5690
|
-
return `${warn}β
Set ${instanceName} to \`${model}\` and restarted
|
|
5727
|
+
return `${warn}β
Set ${instanceName} to \`${model}\` and restarted.${this.effortSuffix(instanceName)}`;
|
|
5728
|
+
}
|
|
5729
|
+
/**
|
|
5730
|
+
* The trailing "Current effort: β¦" line for a /model reply.
|
|
5731
|
+
*
|
|
5732
|
+
* Model and effort interact (a cheaper model at max effort is a different
|
|
5733
|
+
* trade than a bigger one at low), so showing the effort in force right after
|
|
5734
|
+
* a switch saves the round trip of asking. Empty when the backend has none.
|
|
5735
|
+
*/
|
|
5736
|
+
effortSuffix(instanceName) {
|
|
5737
|
+
if (this.effortLevelsFor(instanceName).length === 0)
|
|
5738
|
+
return "";
|
|
5739
|
+
const { effort, source } = this.resolveInstanceEffort(instanceName);
|
|
5740
|
+
if (!effort)
|
|
5741
|
+
return "\nCurrent effort: (CLI default)";
|
|
5742
|
+
return source === "fleet-default"
|
|
5743
|
+
? `\nCurrent effort: ${effort} (fleet default)`
|
|
5744
|
+
: `\nCurrent effort: ${effort}`;
|
|
5691
5745
|
}
|
|
5692
5746
|
/** Read recent chat log for agent context */
|
|
5693
5747
|
getRecentChatLog(instanceName, maxLines = 10) {
|