@songsid/agend 2.1.8-beta.10 → 2.1.8-beta.12
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/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/fleet-manager.d.ts +27 -0
- package/dist/fleet-manager.js +106 -21
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +5 -2
- package/dist/outbound-schemas.d.ts +2 -0
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/status-emojis.d.ts +9 -1
- package/dist/status-emojis.js +11 -1
- package/dist/status-emojis.js.map +1 -1
- package/dist/target-queue-worker.d.ts +67 -0
- package/dist/target-queue-worker.js +76 -0
- package/dist/target-queue-worker.js.map +1 -0
- package/dist/tool-permissions.js +7 -2
- package/dist/tool-permissions.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/ui/settings.html +2 -2
- package/package.json +1 -1
|
@@ -110,7 +110,7 @@ const DEFS = [
|
|
|
110
110
|
["preview_emojis", schemas.PreviewEmojisArgs,
|
|
111
111
|
"Download up to 8 Discord server emojis from list_emojis so you can see them: returns a local image path per emoji to Read before you pick one."],
|
|
112
112
|
["set_persona_emoji", schemas.SetPersonaEmojiArgs,
|
|
113
|
-
"Set your persona emoji: the status stamp (default: delivered) your bot puts on messages it handles, so people can tell you apart from other bots. Validated the way Settings validates it; takes effect on your next stamp."],
|
|
113
|
+
"Set your persona emoji: the status stamp (default: delivered) your bot puts on messages it handles, so people can tell you apart from other bots. Other statuses: received, queued, processing, failed, progress_prefix, and photo / attachment (the stamp on a photo / file your bot saved). Validated the way Settings validates it; takes effect on your next stamp."],
|
|
114
114
|
["set_description", schemas.SetDescriptionArgs,
|
|
115
115
|
"Set your role description. This is injected into your system prompt as your role definition. Takes effect on next session restart."],
|
|
116
116
|
["checkout_repo", schemas.CheckoutRepoArgs,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/channel/mcp-tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/channel/mcp-tools.ts"],"names":[],"mappings":"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"}
|
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { ClassicChannelManager } from "./classic-channel-manager.js";
|
|
|
26
26
|
import { type ExplicitInstanceRemoval } from "./instance-removal.js";
|
|
27
27
|
import type { InstanceState } from "./backend/types.js";
|
|
28
28
|
import { WakeCoordinator } from "./wake-coordinator.js";
|
|
29
|
+
import { TargetQueueWorker } from "./target-queue-worker.js";
|
|
29
30
|
import { resolveDeliveryWorkerMode } from "./types.js";
|
|
30
31
|
import { type ConnectionMetadata, type ConnectionBinding, type BindingProbe, type SecretApplyJob, type ProviderSecretApplyJob } from "./connection-secrets.js";
|
|
31
32
|
import { type ProviderSecretStatus } from "./provider-secret-registry.js";
|
|
@@ -130,6 +131,12 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
130
131
|
private deliveryOutboxRecovered;
|
|
131
132
|
/** Phase 2b: wakes paused targets for queued durable work (delivery_worker ≠ off). */
|
|
132
133
|
wakeCoordinator: WakeCoordinator | null;
|
|
134
|
+
/**
|
|
135
|
+
* Phase 2c: targets whose durable lane a TargetQueueWorker owns
|
|
136
|
+
* (delivery_worker: on). Granted and released only in the pump's
|
|
137
|
+
* synchronous section and only while the lane is empty; the pump skips them.
|
|
138
|
+
*/
|
|
139
|
+
readonly queueWorkers: Map<string, TargetQueueWorker>;
|
|
133
140
|
private deliveryPumpScheduled;
|
|
134
141
|
private deliveryPumpRunning;
|
|
135
142
|
private deliveryPumpTimer;
|
|
@@ -383,6 +390,17 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
383
390
|
sweepReplyObligations(now?: Date): void;
|
|
384
391
|
private scheduleDeliveryOutboxPump;
|
|
385
392
|
private runDeliveryOutboxPump;
|
|
393
|
+
/**
|
|
394
|
+
* Phase 2c ownership (design §1.5-A), called synchronously from the pump
|
|
395
|
+
* before its claim loop, so a grant and the pump's own claims cannot
|
|
396
|
+
* interleave. A worker is granted a target's lane only when the target is
|
|
397
|
+
* `on` and its lane is empty: no row in flight in the outbox and no pump
|
|
398
|
+
* dispatch holding it. It gives the lane back only when it is idle and the
|
|
399
|
+
* target is no longer `on` (or has nothing pending). A flag change never
|
|
400
|
+
* takes a lane mid-drain.
|
|
401
|
+
*/
|
|
402
|
+
private reconcileQueueWorkers;
|
|
403
|
+
private createQueueWorker;
|
|
386
404
|
private dispatchDurableDelivery;
|
|
387
405
|
private waitForDurableLaneRelease;
|
|
388
406
|
private spawnConcurrency;
|
|
@@ -1216,6 +1234,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1216
1234
|
* An empty emoji removes that status's override.
|
|
1217
1235
|
*/
|
|
1218
1236
|
setPersonaEmoji(instanceName: string, args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
1237
|
+
/** A ClassicBot instance: it may see (list/preview) emojis, never set a per-instance stamp. */
|
|
1238
|
+
private isClassicPersonaTarget;
|
|
1219
1239
|
private personaEmojiMissing;
|
|
1220
1240
|
/** What the instructions tell `instanceName` not to react with (its own status set). */
|
|
1221
1241
|
statusEmojiAvoidList(instanceName: string): string[];
|
|
@@ -1236,6 +1256,13 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1236
1256
|
* own adapter rather than through reactMessageStatus (classic bots).
|
|
1237
1257
|
*/
|
|
1238
1258
|
private receivedReactionFor;
|
|
1259
|
+
/**
|
|
1260
|
+
* The stamp for an inbound photo / file a classic bot saved (#1080): the
|
|
1261
|
+
* instance's `status_emojis.photo|attachment`, then its connection's, then
|
|
1262
|
+
* the built-in (📸/📎, or 👌/👍 on Telegram — what these paths always stamped).
|
|
1263
|
+
* Anything else a saved attachment can be counts as a file.
|
|
1264
|
+
*/
|
|
1265
|
+
private savedAttachmentReactionFor;
|
|
1239
1266
|
reactMessageStatus(instanceName: string, chatId: string, messageId: string, status: DeliveryStatus, threadId?: string): void;
|
|
1240
1267
|
/**
|
|
1241
1268
|
* Apply a terminal delivery verdict. On Telegram the built-in delivered is
|
package/dist/fleet-manager.js
CHANGED
|
@@ -68,6 +68,7 @@ import { validateFleetConfig } from "./config-validator.js";
|
|
|
68
68
|
import { readLastInboundAt } from "./daemon.js";
|
|
69
69
|
import { clearPausedMarker, readPausedAt, readPauseReason, writePausedMarker } from "./pause-marker.js";
|
|
70
70
|
import { DEFAULT_WARM_OVERFLOW, WakeCoordinator } from "./wake-coordinator.js";
|
|
71
|
+
import { TargetQueueWorker } from "./target-queue-worker.js";
|
|
71
72
|
import { resolveDeliveryWorkerMode } from "./types.js";
|
|
72
73
|
import { isFleetStartCommandLine, readProcessCommandLine, releaseProcessFleetLock } from "./fleet-lock.js";
|
|
73
74
|
import { isSetupComplete, markSetupComplete } from "./setup-marker.js";
|
|
@@ -290,6 +291,12 @@ export class FleetManager {
|
|
|
290
291
|
deliveryOutboxRecovered = false;
|
|
291
292
|
/** Phase 2b: wakes paused targets for queued durable work (delivery_worker ≠ off). */
|
|
292
293
|
wakeCoordinator = null;
|
|
294
|
+
/**
|
|
295
|
+
* Phase 2c: targets whose durable lane a TargetQueueWorker owns
|
|
296
|
+
* (delivery_worker: on). Granted and released only in the pump's
|
|
297
|
+
* synchronous section and only while the lane is empty; the pump skips them.
|
|
298
|
+
*/
|
|
299
|
+
queueWorkers = new Map();
|
|
293
300
|
deliveryPumpScheduled = false;
|
|
294
301
|
deliveryPumpRunning = false;
|
|
295
302
|
deliveryPumpTimer = null;
|
|
@@ -729,11 +736,13 @@ export class FleetManager {
|
|
|
729
736
|
const failure = this.wakeCoordinator?.wakeFailure(target);
|
|
730
737
|
return failure ? `target could not be woken (${failure})` : undefined;
|
|
731
738
|
});
|
|
739
|
+
this.reconcileQueueWorkers(outbox);
|
|
732
740
|
while (this.activeDurableTargets.size < 8) {
|
|
733
741
|
const claimed = outbox.claimNext(this.managerBootId,
|
|
734
742
|
// Phase 2b: a wake_only target is claimed only once it is awake; the
|
|
735
743
|
// wake coordinator, not this pump, wakes it (no claim, no attempt).
|
|
736
|
-
|
|
744
|
+
// Phase 2c: a lane a queue worker owns is never claimed here.
|
|
745
|
+
target => this.queueWorkers.has(target) || this.isInstanceRestarting(target) || this.wakeCoordinator?.blocksClaim(target)
|
|
737
746
|
? null
|
|
738
747
|
: this.daemons.get(target)?.bootId ?? null, this.activeDurableTargets);
|
|
739
748
|
if (!claimed)
|
|
@@ -763,7 +772,67 @@ export class FleetManager {
|
|
|
763
772
|
}
|
|
764
773
|
}
|
|
765
774
|
}
|
|
766
|
-
|
|
775
|
+
/**
|
|
776
|
+
* Phase 2c ownership (design §1.5-A), called synchronously from the pump
|
|
777
|
+
* before its claim loop, so a grant and the pump's own claims cannot
|
|
778
|
+
* interleave. A worker is granted a target's lane only when the target is
|
|
779
|
+
* `on` and its lane is empty: no row in flight in the outbox and no pump
|
|
780
|
+
* dispatch holding it. It gives the lane back only when it is idle and the
|
|
781
|
+
* target is no longer `on` (or has nothing pending). A flag change never
|
|
782
|
+
* takes a lane mid-drain.
|
|
783
|
+
*/
|
|
784
|
+
reconcileQueueWorkers(outbox) {
|
|
785
|
+
const pendingTargets = new Set(outbox.listPending().map(row => row.targetInstance));
|
|
786
|
+
for (const [target, worker] of this.queueWorkers) {
|
|
787
|
+
const keep = this.deliveryWorkerMode(target) === "on" && pendingTargets.has(target);
|
|
788
|
+
if (!keep && !worker.busy && !worker.inFlight)
|
|
789
|
+
this.queueWorkers.delete(target);
|
|
790
|
+
}
|
|
791
|
+
for (const target of pendingTargets) {
|
|
792
|
+
if (this.queueWorkers.has(target) || this.deliveryWorkerMode(target) !== "on")
|
|
793
|
+
continue;
|
|
794
|
+
const laneEmpty = !this.activeDurableTargets.has(target)
|
|
795
|
+
&& outbox.countForTarget(target, ["delivering", "submission_started"]) === 0;
|
|
796
|
+
if (laneEmpty)
|
|
797
|
+
this.queueWorkers.set(target, this.createQueueWorker(target));
|
|
798
|
+
}
|
|
799
|
+
for (const worker of this.queueWorkers.values())
|
|
800
|
+
void worker.drain();
|
|
801
|
+
}
|
|
802
|
+
createQueueWorker(target) {
|
|
803
|
+
const worker = new TargetQueueWorker(target, {
|
|
804
|
+
owns: () => this.queueWorkers.get(target) === worker,
|
|
805
|
+
wanted: () => this.deliveryWorkerMode(target) === "on",
|
|
806
|
+
available: () => !this.shuttingDown && this.deliveryOutbox?.isOpen === true,
|
|
807
|
+
blocked: () => this.isInstanceRestarting(target) || this.wakeCoordinator?.blocksClaim(target) === true,
|
|
808
|
+
daemonBootId: () => this.daemons.get(target)?.bootId ?? null,
|
|
809
|
+
claim: bootId => this.deliveryOutbox?.claimNext(this.managerBootId, candidate => candidate === target ? bootId : null, new Set()),
|
|
810
|
+
tryAcquireBudget: () => {
|
|
811
|
+
if (this.activeDurableTargets.size >= 8)
|
|
812
|
+
return false;
|
|
813
|
+
this.activeDurableTargets.add(target);
|
|
814
|
+
return true;
|
|
815
|
+
},
|
|
816
|
+
releaseBudget: () => { this.activeDurableTargets.delete(target); },
|
|
817
|
+
dispatch: async (claimed) => {
|
|
818
|
+
try {
|
|
819
|
+
await this.dispatchDurableDelivery(claimed, { holdLaneOnTransportError: true });
|
|
820
|
+
}
|
|
821
|
+
finally {
|
|
822
|
+
// The row's state event can fire before the hand-off settles; the
|
|
823
|
+
// pump pass it starts then still sees this worker busy and keeps it
|
|
824
|
+
// as owner. One kick after the dispatch has really settled lets the
|
|
825
|
+
// pump release an owner that is no longer wanted (or claim the next
|
|
826
|
+
// row). The no-claim path never kicks, so no retry hot loop.
|
|
827
|
+
this.scheduleDeliveryOutboxPump();
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
kickCoordinator: () => this.wakeCoordinator?.kick(),
|
|
831
|
+
logger: this.logger,
|
|
832
|
+
});
|
|
833
|
+
return worker;
|
|
834
|
+
}
|
|
835
|
+
async dispatchDurableDelivery(claimed, opts = {}) {
|
|
767
836
|
const outbox = this.deliveryOutbox;
|
|
768
837
|
if (!outbox)
|
|
769
838
|
return;
|
|
@@ -817,7 +886,10 @@ export class FleetManager {
|
|
|
817
886
|
catch (err) {
|
|
818
887
|
const latest = outbox.get(claimed.deliveryId);
|
|
819
888
|
const reason = err instanceof Error ? err.message : String(err);
|
|
820
|
-
if (latest?.state === "submission_started") {
|
|
889
|
+
if (opts.holdLaneOnTransportError && (latest?.state === "submission_started" || latest?.state === "reconciliation_pending")) {
|
|
890
|
+
this.logger.warn({ deliveryId: claimed.deliveryId, target, attempt, err: reason }, "Transport failed after the submission began; holding the lane for the daemon's verdict or its generation's reconciliation");
|
|
891
|
+
}
|
|
892
|
+
else if (latest?.state === "submission_started") {
|
|
821
893
|
outbox.complete(claimed.deliveryId, claimed.targetDaemonBootId, claimed.attemptNo, "uncertain", reason);
|
|
822
894
|
}
|
|
823
895
|
else {
|
|
@@ -7197,19 +7269,26 @@ export class FleetManager {
|
|
|
7197
7269
|
* Settings picker (#1005/#1021), so an agent and an operator see one truth.
|
|
7198
7270
|
*/
|
|
7199
7271
|
async listEmojisFor(instanceName, refresh = false) {
|
|
7200
|
-
|
|
7201
|
-
|
|
7272
|
+
// Seeing is not setting: a ClassicBot instance has no per-instance stamp,
|
|
7273
|
+
// but it reacts in its own channel like any bot and must be able to see
|
|
7274
|
+
// the emojis it can use (only set_persona_emoji refuses it).
|
|
7275
|
+
// Own entries only: an inherited name (constructor, __proto__, toString…)
|
|
7276
|
+
// is not a fleet instance, as set_persona_emoji already holds.
|
|
7277
|
+
const self = this.ownInstanceConfig(instanceName);
|
|
7278
|
+
const classic = !self && this.isClassicPersonaTarget(instanceName);
|
|
7279
|
+
if (!self && !classic)
|
|
7202
7280
|
return { error: this.personaEmojiMissing(instanceName) };
|
|
7203
7281
|
const worldId = this.getInstanceAdapterId(instanceName);
|
|
7204
7282
|
const { platform } = this.resolveStatusEmojisFor(instanceName);
|
|
7205
7283
|
const channel = (worldId ? this.worlds.get(worldId)?.channelConfig : undefined) ?? this.getChannelConfig(worldId ?? undefined);
|
|
7206
|
-
const current = previewStatusEmojis({ platform, platformConfig: channel?.options?.status_emojis, instanceConfig: self
|
|
7284
|
+
const current = previewStatusEmojis({ platform, platformConfig: channel?.options?.status_emojis, instanceConfig: self?.status_emojis });
|
|
7207
7285
|
const out = {
|
|
7208
7286
|
platform: platform ?? null,
|
|
7209
7287
|
statuses: current.entries.map(e => ({ status: e.key, value: e.value, source: e.source })),
|
|
7210
7288
|
standard: platform === "telegram"
|
|
7211
7289
|
? { reactions: [...TELEGRAM_REACTION_EMOJIS], note: "Telegram reacts only with these; progress_prefix may be any single emoji" }
|
|
7212
7290
|
: { suggestions: STATUS_EMOJI_SUGGESTIONS, note: "any single emoji works" },
|
|
7291
|
+
...(classic ? { note: "ClassicBot instances have no per-instance status emojis: the statuses above are the connection's, which an operator sets in Settings. You can still use any emoji listed here in your own reactions." } : {}),
|
|
7213
7292
|
};
|
|
7214
7293
|
if (platform === "discord" && worldId) {
|
|
7215
7294
|
const listed = await this.listGuildEmojis(worldId, refresh);
|
|
@@ -7240,9 +7319,10 @@ export class FleetManager {
|
|
|
7240
7319
|
* from that listed emoji's numeric id. Static PNG, size-capped, cached by id.
|
|
7241
7320
|
*/
|
|
7242
7321
|
async previewEmojis(instanceName, args) {
|
|
7243
|
-
|
|
7244
|
-
if (!
|
|
7322
|
+
// Seeing, like list_emojis: ClassicBot instances may preview too.
|
|
7323
|
+
if (!this.ownInstanceConfig(instanceName) && !this.isClassicPersonaTarget(instanceName)) {
|
|
7245
7324
|
return { error: this.personaEmojiMissing(instanceName) };
|
|
7325
|
+
}
|
|
7246
7326
|
const wanted = args.emojis;
|
|
7247
7327
|
if (!Array.isArray(wanted) || wanted.length === 0 || wanted.some(e => typeof e !== "string")) {
|
|
7248
7328
|
return { error: "emojis is required: a list of <:name:id> values from list_emojis" };
|
|
@@ -7401,6 +7481,10 @@ export class FleetManager {
|
|
|
7401
7481
|
const resolved = this.resolveStatusEmojisFor(instanceName);
|
|
7402
7482
|
return { status, value: value ?? null, now: resolved[status], status_emojis: current.status_emojis ?? null };
|
|
7403
7483
|
}
|
|
7484
|
+
/** A ClassicBot instance: it may see (list/preview) emojis, never set a per-instance stamp. */
|
|
7485
|
+
isClassicPersonaTarget(instanceName) {
|
|
7486
|
+
return this.classicChannels?.getAll().some(c => c.instanceName === instanceName) ?? false;
|
|
7487
|
+
}
|
|
7404
7488
|
personaEmojiMissing(instanceName) {
|
|
7405
7489
|
return this.classicChannels?.getAll().some(c => c.instanceName === instanceName)
|
|
7406
7490
|
? "ClassicBot instances have no per-instance status emojis; an operator sets the connection's in Settings"
|
|
@@ -7462,6 +7546,16 @@ export class FleetManager {
|
|
|
7462
7546
|
const resolved = this.resolveStatusEmojisFor(instanceName, adapterId, adapter);
|
|
7463
7547
|
return reactionForm(resolved.platform, resolved.received);
|
|
7464
7548
|
}
|
|
7549
|
+
/**
|
|
7550
|
+
* The stamp for an inbound photo / file a classic bot saved (#1080): the
|
|
7551
|
+
* instance's `status_emojis.photo|attachment`, then its connection's, then
|
|
7552
|
+
* the built-in (📸/📎, or 👌/👍 on Telegram — what these paths always stamped).
|
|
7553
|
+
* Anything else a saved attachment can be counts as a file.
|
|
7554
|
+
*/
|
|
7555
|
+
savedAttachmentReactionFor(instanceName, adapter, adapterId, kind) {
|
|
7556
|
+
const resolved = this.resolveStatusEmojisFor(instanceName, adapterId, adapter);
|
|
7557
|
+
return reactionForm(resolved.platform, kind === "photo" ? resolved.photo : resolved.attachment);
|
|
7558
|
+
}
|
|
7465
7559
|
reactMessageStatus(instanceName, chatId, messageId, status, threadId) {
|
|
7466
7560
|
// React via the adapter BOUND to this instance — NOT the first discord world.
|
|
7467
7561
|
// Otherwise, in a same-channel/same-guild multi-bot setup, the inbound 👀
|
|
@@ -10579,9 +10673,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
10579
10673
|
const reactAdapter = this.worlds.get(msg.adapterId ?? "")?.adapter ?? this.adapter;
|
|
10580
10674
|
const noMentionReactChatId = msg.threadId ?? msg.chatId;
|
|
10581
10675
|
if (reactAdapter && noMentionReactChatId && msg.messageId) {
|
|
10582
|
-
const emoji = msg.
|
|
10583
|
-
? (saved.kind === "photo" ? "👌" : "👍")
|
|
10584
|
-
: (saved.kind === "photo" ? "📸" : "📎");
|
|
10676
|
+
const emoji = this.savedAttachmentReactionFor(instanceName, reactAdapter, msg.adapterId, saved.kind);
|
|
10585
10677
|
reactAdapter.react(noMentionReactChatId, msg.messageId, emoji)
|
|
10586
10678
|
.catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
|
|
10587
10679
|
}
|
|
@@ -10612,9 +10704,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
10612
10704
|
return;
|
|
10613
10705
|
// Attachments already saved at the top of the collab block.
|
|
10614
10706
|
if (saved && classicAdapter && collabReactChatId && msg.messageId) {
|
|
10615
|
-
const emoji = msg.
|
|
10616
|
-
? (saved.kind === "photo" ? "👌" : "👍")
|
|
10617
|
-
: (saved.kind === "photo" ? "📸" : "📎");
|
|
10707
|
+
const emoji = this.savedAttachmentReactionFor(instanceName, classicAdapter, msg.adapterId, saved.kind);
|
|
10618
10708
|
classicAdapter.react(collabReactChatId, msg.messageId, emoji)
|
|
10619
10709
|
.catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
|
|
10620
10710
|
}
|
|
@@ -10662,10 +10752,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
10662
10752
|
const reactAdapter = this.worlds.get(msg.adapterId ?? "")?.adapter ?? this.adapter;
|
|
10663
10753
|
const reactChatId = msg.threadId ?? msg.chatId;
|
|
10664
10754
|
if (saved && reactAdapter && reactChatId && msg.messageId) {
|
|
10665
|
-
|
|
10666
|
-
const emoji = msg.source === "telegram"
|
|
10667
|
-
? (saved.kind === "photo" ? "👌" : "👍")
|
|
10668
|
-
: (saved.kind === "photo" ? "📸" : "📎");
|
|
10755
|
+
const emoji = this.savedAttachmentReactionFor(instanceName, reactAdapter, msg.adapterId, saved.kind);
|
|
10669
10756
|
reactAdapter.react(reactChatId, msg.messageId, emoji)
|
|
10670
10757
|
.catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
|
|
10671
10758
|
}
|
|
@@ -10711,9 +10798,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
10711
10798
|
classicMsgAdapter.react(reactChatId, msg.messageId, this.receivedReactionFor(instanceName, classicMsgAdapter, msg.adapterId))
|
|
10712
10799
|
.catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
|
|
10713
10800
|
if (saved) {
|
|
10714
|
-
const savedEmoji = msg.
|
|
10715
|
-
? (saved.kind === "photo" ? "👌" : "👍")
|
|
10716
|
-
: (saved.kind === "photo" ? "📸" : "📎");
|
|
10801
|
+
const savedEmoji = this.savedAttachmentReactionFor(instanceName, classicMsgAdapter, msg.adapterId, saved.kind);
|
|
10717
10802
|
classicMsgAdapter.react(reactChatId, msg.messageId, savedEmoji)
|
|
10718
10803
|
.catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
|
|
10719
10804
|
}
|