agent-relay-runner 0.105.1 → 0.106.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-runner",
3
- "version": "0.105.1",
3
+ "version": "0.106.0",
4
4
  "description": "Unified provider lifecycle runner for Agent Relay",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-relay-runner",
3
3
  "description": "Thin Agent Relay runner bridge for Claude Code",
4
- "version": "0.105.1",
4
+ "version": "0.106.0",
5
5
  "agentRelayContracts": {
6
6
  "providerPluginProtocol": 1
7
7
  }
@@ -1035,6 +1035,17 @@ var NOTIFICATION_NUDGE = "\u21AA Notification \u2014 no reply needed.";
1035
1035
  function isNotificationMessage(message) {
1036
1036
  return isPersistedRelayMessage(message) && message.replyExpected === false;
1037
1037
  }
1038
+ function dedupePersistedMessages(messages2) {
1039
+ const seen = new Set;
1040
+ return messages2.filter((message) => {
1041
+ if (!isPersistedRelayMessage(message))
1042
+ return true;
1043
+ if (seen.has(message.id))
1044
+ return false;
1045
+ seen.add(message.id);
1046
+ return true;
1047
+ });
1048
+ }
1038
1049
  function providerAttachmentText(message) {
1039
1050
  const refs = attachmentRefs(message);
1040
1051
  if (!refs.length)
@@ -1165,11 +1176,12 @@ function replyReminder(message, readOnly) {
1165
1176
  }
1166
1177
  function claudeProviderMessageText(messages2, options) {
1167
1178
  const relaySurface = options.relaySurface !== false;
1168
- const sections = messages2.map((message) => formatMessage(message, relaySurface));
1169
- const replyable = latestReplyableMessage(messages2);
1179
+ const uniqueMessages = dedupePersistedMessages(messages2);
1180
+ const sections = uniqueMessages.map((message) => formatMessage(message, relaySurface));
1181
+ const replyable = latestReplyableMessage(uniqueMessages);
1170
1182
  if (relaySurface && replyable && shouldShowReplyReminder(options.deliveryCount)) {
1171
1183
  sections.push(replyReminder(replyable, options.readOnly === true));
1172
- } else if (relaySurface && !replyable && messages2.some(isNotificationMessage)) {
1184
+ } else if (relaySurface && !replyable && uniqueMessages.some(isNotificationMessage)) {
1173
1185
  sections.push(NOTIFICATION_NUDGE);
1174
1186
  }
1175
1187
  return sections.join(`
package/src/adapter.ts CHANGED
@@ -304,6 +304,16 @@ function latestReplyableMessage(messages: Message[]): Message | undefined {
304
304
  .at(-1);
305
305
  }
306
306
 
307
+ export function dedupePersistedMessages(messages: Message[]): Message[] {
308
+ const seen = new Set<number>();
309
+ return messages.filter((message) => {
310
+ if (!isPersistedRelayMessage(message)) return true;
311
+ if (seen.has(message.id)) return false;
312
+ seen.add(message.id);
313
+ return true;
314
+ });
315
+ }
316
+
307
317
  function providerSenderLabel(message: Message): string {
308
318
  if (message.from === "user") return "human user";
309
319
  const source = isRecord(message.payload?.source) ? message.payload.source : undefined;
@@ -356,9 +366,10 @@ export function providerAttachmentText(message: Message): string | undefined {
356
366
  }
357
367
 
358
368
  export function providerMessageText(messages: Message[]): string {
359
- const replyable = latestReplyableMessage(messages);
369
+ const uniqueMessages = dedupePersistedMessages(messages);
370
+ const replyable = latestReplyableMessage(uniqueMessages);
360
371
  const maxChars = providerMessageBodyMaxChars();
361
- const sections = messages
372
+ const sections = uniqueMessages
362
373
  .map((message) => {
363
374
  const subject = message.subject ? `Subject: ${message.subject}\n` : "";
364
375
  const isMemoryContext = isMemoryInjection(message);
@@ -404,7 +415,7 @@ export function providerMessageText(messages: Message[]): string {
404
415
  "If you already delivered the useful response through Relay, do not send a separate status-only confirmation.",
405
416
  "If multiple messages arrived together, cover them in one reply instead of answering each line separately.",
406
417
  ].join("\n"));
407
- } else if (messages.some(isNotificationMessage)) {
418
+ } else if (uniqueMessages.some(isNotificationMessage)) {
408
419
  // #283 — pure notification batch: no scaffold, just the one-line no-reply nudge.
409
420
  sections.push(NOTIFICATION_NUDGE);
410
421
  }
@@ -1,6 +1,6 @@
1
1
  import type { Message } from "agent-relay-sdk";
2
2
  import { isRecord } from "agent-relay-sdk";
3
- import { isNotificationMessage, NOTIFICATION_NUDGE, providerAttachmentText, providerMessageBodyMaxChars } from "../adapter";
3
+ import { dedupePersistedMessages, isNotificationMessage, NOTIFICATION_NUDGE, providerAttachmentText, providerMessageBodyMaxChars } from "../adapter";
4
4
  import { relayReplyReminderText } from "../relay-instructions";
5
5
 
6
6
  const REMINDER_EVERY_DELIVERIES = 5;
@@ -126,12 +126,13 @@ function replyReminder(message: Message, readOnly: boolean): string {
126
126
 
127
127
  export function claudeProviderMessageText(messages: Message[], options: ClaudeDeliveryTextOptions): string {
128
128
  const relaySurface = options.relaySurface !== false;
129
- const sections = messages.map((message) => formatMessage(message, relaySurface));
130
- const replyable = latestReplyableMessage(messages);
129
+ const uniqueMessages = dedupePersistedMessages(messages);
130
+ const sections = uniqueMessages.map((message) => formatMessage(message, relaySurface));
131
+ const replyable = latestReplyableMessage(uniqueMessages);
131
132
  // Isolated agents have no way to reply through Relay — never append the reminder/nudge.
132
133
  if (relaySurface && replyable && shouldShowReplyReminder(options.deliveryCount)) {
133
134
  sections.push(replyReminder(replyable, options.readOnly === true));
134
- } else if (relaySurface && !replyable && messages.some(isNotificationMessage)) {
135
+ } else if (relaySurface && !replyable && uniqueMessages.some(isNotificationMessage)) {
135
136
  // #283 — pure notification batch (no message wants a reply): drop the scaffold, append the
136
137
  // one-line nudge so a long context can't make the agent forget the session-start no-reply rule.
137
138
  sections.push(NOTIFICATION_NUDGE);