@songsid/agend 2.1.5-beta.15 → 2.1.5-beta.16

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.
@@ -331,6 +331,26 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
331
331
  getWorldForInstance(name: string): AdapterWorld | undefined;
332
332
  /** Get channel config for a specific adapter (by id), falling back to primary */
333
333
  getChannelConfig(adapterId?: string): import("./types.js").ChannelConfig | undefined;
334
+ /**
335
+ * The configured world that owns `chatId`, when that is provably NOT the
336
+ * world `target` lives in. Returns undefined when they agree, when there is
337
+ * nothing to check, or when no configured channel claims the id.
338
+ *
339
+ * Deliberately one-sided: only a POSITIVE match against another channel's
340
+ * group id counts as foreign. A chat id that matches nothing may still be
341
+ * legitimate for this world (a classic channel, a DM), and treating
342
+ * "unrecognised" as "wrong" would stop seeding for cases that work today.
343
+ *
344
+ * Read from config rather than the live worlds map on purpose: a channel
345
+ * whose adapter failed to start still owns its group id, and the coordinates
346
+ * are just as unusable by the target's adapter either way.
347
+ *
348
+ * This is the other half of what scheduleSourceAdapter fixed. That one stops
349
+ * the trigger NOTICE being sent through the wrong bot; this one stops the
350
+ * same coordinates being planted as the target instance's reply context,
351
+ * which is what made its own replies fail until someone spoke to it (#752).
352
+ */
353
+ private scheduleChatWorldMismatch;
334
354
  /** Get the group_id for an instance's bound adapter */
335
355
  getGroupIdForInstance(name: string): string;
336
356
  /** Configured primary adapter id. Never infer this from Map insertion order. */
@@ -928,6 +928,45 @@ export class FleetManager {
928
928
  }
929
929
  return channels[0];
930
930
  }
931
+ /**
932
+ * The configured world that owns `chatId`, when that is provably NOT the
933
+ * world `target` lives in. Returns undefined when they agree, when there is
934
+ * nothing to check, or when no configured channel claims the id.
935
+ *
936
+ * Deliberately one-sided: only a POSITIVE match against another channel's
937
+ * group id counts as foreign. A chat id that matches nothing may still be
938
+ * legitimate for this world (a classic channel, a DM), and treating
939
+ * "unrecognised" as "wrong" would stop seeding for cases that work today.
940
+ *
941
+ * Read from config rather than the live worlds map on purpose: a channel
942
+ * whose adapter failed to start still owns its group id, and the coordinates
943
+ * are just as unusable by the target's adapter either way.
944
+ *
945
+ * This is the other half of what scheduleSourceAdapter fixed. That one stops
946
+ * the trigger NOTICE being sent through the wrong bot; this one stops the
947
+ * same coordinates being planted as the target instance's reply context,
948
+ * which is what made its own replies fail until someone spoke to it (#752).
949
+ */
950
+ scheduleChatWorldMismatch(target, chatId) {
951
+ if (!chatId)
952
+ return undefined;
953
+ const targetWorld = this.getInstanceAdapterId(target);
954
+ if (!targetWorld)
955
+ return undefined;
956
+ const channels = this.fleetConfig?.channels
957
+ ?? (this.fleetConfig?.channel ? [this.fleetConfig.channel] : []);
958
+ // ALL owners, not the first: a persona bot shares the primary's guild
959
+ // (quickstart writes `group_id: primary.group_id`), so one group id is
960
+ // legitimately claimed by two channels. Taking the first match called a
961
+ // persona instance's own guild "another world" and stopped seeding a
962
+ // context it can address perfectly well.
963
+ const owners = channels.filter(ch => ch.group_id != null && String(ch.group_id) === String(chatId));
964
+ if (owners.length === 0)
965
+ return undefined;
966
+ if (owners.some(ch => (ch.id ?? ch.type) === targetWorld))
967
+ return undefined;
968
+ return owners[0].id ?? owners[0].type;
969
+ }
931
970
  /** Get the group_id for an instance's bound adapter */
932
971
  getGroupIdForInstance(name) {
933
972
  const adapterId = this.getInstanceAdapterId(name);
@@ -4894,12 +4933,25 @@ export class FleetManager {
4894
4933
  // the target instance's configured world so replies use its persona
4895
4934
  // after a fresh start instead of falling back to channels[0].
4896
4935
  const adapterId = this.getInstanceAdapterId(target);
4936
+ // ...but the stored reply coordinates belong to the chat the schedule
4937
+ // was CREATED in, which is not always the target's world. Pairing them
4938
+ // with the target's adapter hands one platform's ids to another's API:
4939
+ // a Telegram group + forum topic delivered to a Discord instance made
4940
+ // every reply on that turn fetch `/channels/<telegram topic>` and fail
4941
+ // with Unknown Channel, and because the seeding repeats on each trigger
4942
+ // it stayed broken until a real inbound overwrote the context (#752).
4943
+ const foreignWorld = this.scheduleChatWorldMismatch(target, reply_chat_id);
4944
+ if (foreignWorld) {
4945
+ this.logger.warn({ scheduleId: id, target, foreignWorld, targetWorld: adapterId, chatId: reply_chat_id }, "Schedule reply target belongs to another channel world — not seeding chat context; the instance keeps its own last known chat");
4946
+ }
4897
4947
  await this.deliverToInstance(target, {
4898
4948
  type: "fleet_schedule_trigger",
4899
4949
  payload: { schedule_id: id, message: `[Scheduled] ${message}`, label },
4900
4950
  meta: {
4901
- chat_id: reply_chat_id,
4902
- thread_id: reply_thread_id,
4951
+ // Omitted on a mismatch: the daemon then keeps its persisted
4952
+ // last-chat, which is in the right world, instead of being
4953
+ // overwritten with coordinates the target's adapter cannot address.
4954
+ ...(foreignWorld ? {} : { chat_id: reply_chat_id, thread_id: reply_thread_id }),
4903
4955
  user: "scheduler",
4904
4956
  ...(adapterId ? { adapter_id: adapterId } : {}),
4905
4957
  },