agent-relay-runner 0.10.14 → 0.10.15

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.10.14",
3
+ "version": "0.10.15",
4
4
  "description": "Unified provider lifecycle runner for Agent Relay",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "agent-relay-runner",
3
3
  "description": "Thin Agent Relay runner bridge for Claude Code",
4
- "version": "0.10.14"
4
+ "version": "0.10.15"
5
5
  }
package/src/runner.ts CHANGED
@@ -40,6 +40,7 @@ export class AgentRunner {
40
40
  private stopped = false;
41
41
  private exitCommandInProgress = false;
42
42
  private delivering = false;
43
+ private drainTimer?: Timer;
43
44
  private readonly pendingMessages = new Map<number, Message>();
44
45
 
45
46
  constructor(private readonly options: RunnerOptions) {
@@ -104,6 +105,8 @@ export class AgentRunner {
104
105
  await this.bus.connect();
105
106
  this.process = await this.spawnProvider();
106
107
  this.publishStatus();
108
+ await this.bootstrapUnreadMessages();
109
+ this.scheduleDrain();
107
110
  }
108
111
 
109
112
  async stop(): Promise<void> {
@@ -116,6 +119,8 @@ export class AgentRunner {
116
119
  timeoutMs: this.options.providerConfig.headless.shutdownTimeoutMs,
117
120
  });
118
121
  }
122
+ if (this.drainTimer) clearTimeout(this.drainTimer);
123
+ this.drainTimer = undefined;
119
124
  this.control?.stop();
120
125
  await this.bus.close();
121
126
  }
@@ -157,11 +162,32 @@ export class AgentRunner {
157
162
  private enqueueMessage(message: Message): void {
158
163
  if (!this.matchesMessage(message)) return;
159
164
  this.pendingMessages.set(message.id, message);
160
- void this.drainMessages();
165
+ this.scheduleDrain();
166
+ }
167
+
168
+ private async bootstrapUnreadMessages(): Promise<void> {
169
+ try {
170
+ const messages = await this.http.pollMessages({ for: this.agentId, unread: true, limit: 100 });
171
+ for (const message of messages) this.enqueueMessage(message);
172
+ } catch (error) {
173
+ console.error(`[runner] inbox bootstrap failed: ${error}`);
174
+ }
175
+ }
176
+
177
+ private scheduleDrain(delayMs = 0): void {
178
+ if (this.stopped || this.drainTimer) return;
179
+ this.drainTimer = setTimeout(() => {
180
+ this.drainTimer = undefined;
181
+ void this.drainMessages();
182
+ }, delayMs);
161
183
  }
162
184
 
163
185
  private async drainMessages(): Promise<void> {
164
- if (this.delivering || this.pendingMessages.size === 0 || !this.process) return;
186
+ if (this.stopped || this.delivering || this.pendingMessages.size === 0) return;
187
+ if (!this.process) {
188
+ this.scheduleDrain(500);
189
+ return;
190
+ }
165
191
  this.delivering = true;
166
192
  const messages = [...this.pendingMessages.values()].sort((a, b) => a.id - b.id);
167
193
  this.pendingMessages.clear();
@@ -173,16 +199,21 @@ export class AgentRunner {
173
199
  }
174
200
  }
175
201
  this.publishStatus();
202
+ let failed = false;
176
203
  try {
177
204
  await this.options.adapter.deliver(this.process, messages);
178
205
  for (const message of messages) {
179
206
  await this.http.markRead(message.id, this.agentId).catch(() => {});
180
207
  this.claims.finishClaim("message", String(message.id));
181
208
  }
209
+ } catch (error) {
210
+ failed = true;
211
+ console.error(`[runner] message delivery failed: ${error}`);
212
+ for (const message of messages) this.pendingMessages.set(message.id, message);
182
213
  } finally {
183
214
  this.delivering = false;
184
215
  this.publishStatus();
185
- if (this.pendingMessages.size > 0) void this.drainMessages();
216
+ if (this.pendingMessages.size > 0) this.scheduleDrain(failed ? 1000 : 0);
186
217
  }
187
218
  }
188
219