agent-relay-runner 0.37.0 → 0.38.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.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Unified provider lifecycle runner for Agent Relay",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,7 +20,7 @@
20
20
  "directory": "runner"
21
21
  },
22
22
  "dependencies": {
23
- "agent-relay-sdk": "0.2.22"
23
+ "agent-relay-sdk": "0.2.23"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/bun": "latest",
@@ -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.37.0",
4
+ "version": "0.38.0",
5
5
  "agentRelayContracts": {
6
6
  "providerPluginProtocol": 1
7
7
  }
package/src/runner.ts CHANGED
@@ -250,6 +250,7 @@ export class AgentRunner {
250
250
  // Session-mirror: a synthesized id grouping a turn's reasoning/tool steps and
251
251
  // its final response. Set when a provider-turn starts, cleared when it ends.
252
252
  private currentTurnId?: string;
253
+ private currentTurnStartedAt?: number;
253
254
  // Prompt-echo dedup: a short, time-bounded queue of prompts the runner itself
254
255
  // injected (chat box or initial prompt) that are still awaiting their matching
255
256
  // UserPromptSubmit echo. A single slot dropped earlier entries when several prompts
@@ -1094,12 +1095,14 @@ export class AgentRunner {
1094
1095
  if (status === "busy" && reason === "provider-turn") {
1095
1096
  if (!this.currentTurnId) {
1096
1097
  this.currentTurnId = typeof update !== "string" && update.id ? update.id : crypto.randomUUID();
1098
+ this.currentTurnStartedAt = Date.now();
1097
1099
  this.sessionLog(`turn started (turn ${this.currentTurnId})`);
1098
1100
  }
1099
1101
  this.armBusyReconciler();
1100
1102
  } else if (status === "idle" && reason === "provider-turn") {
1101
1103
  if (this.currentTurnId) this.sessionLog(`turn ended via provider idle (turn ${this.currentTurnId})`);
1102
1104
  this.currentTurnId = undefined;
1105
+ this.currentTurnStartedAt = undefined;
1103
1106
  this.disarmBusyReconciler();
1104
1107
  this.stopReasoningTail();
1105
1108
  }
@@ -1324,7 +1327,10 @@ export class AgentRunner {
1324
1327
  // deliveries) so those aren't double-posted.
1325
1328
  private async handleUserPrompt(input: { prompt: string; transcriptPath?: string }): Promise<void> {
1326
1329
  if (input.transcriptPath) this.lastTranscriptPath = input.transcriptPath;
1327
- if (!this.currentTurnId) this.currentTurnId = crypto.randomUUID();
1330
+ if (!this.currentTurnId) {
1331
+ this.currentTurnId = crypto.randomUUID();
1332
+ this.currentTurnStartedAt = Date.now();
1333
+ }
1328
1334
  const text = input.prompt.trim();
1329
1335
  if (text && !this.isRunnerInjectedPrompt(text)) {
1330
1336
  this.sessionLog(`prompt echoed from terminal (${text.length} chars)`);
@@ -1482,7 +1488,7 @@ export class AgentRunner {
1482
1488
  if (pendingPrompt) {
1483
1489
  replyToMessageId = pendingPrompt;
1484
1490
  this.pendingPromptMessageId = undefined;
1485
- } else if (this.obligationCache.get().some((o) => o.from === "user")) {
1491
+ } else if (this.obligationCache.get().some((o) => o.from === "user" && this.obligationPredatesCurrentTurn(o))) {
1486
1492
  // The agent will answer the relay obligation itself — don't double-post (#196).
1487
1493
  return;
1488
1494
  }
@@ -1534,6 +1540,10 @@ export class AgentRunner {
1534
1540
  return false;
1535
1541
  }
1536
1542
 
1543
+ private obligationPredatesCurrentTurn(obligation: { createdAt: number }): boolean {
1544
+ return this.currentTurnStartedAt === undefined || obligation.createdAt <= this.currentTurnStartedAt;
1545
+ }
1546
+
1537
1547
  // --- Busy-state reconciler (item 2) -------------------------------------------------
1538
1548
  // A safety net for turns that end out of band (interrupted from the web terminal,
1539
1549
  // a hook that never fired) where the runner would otherwise stay stuck "busy".
@@ -1668,6 +1678,7 @@ export class AgentRunner {
1668
1678
  }
1669
1679
 
1670
1680
  private publishStatus(): void {
1681
+ this.claims.expire();
1671
1682
  const status = this.claims.currentStatus();
1672
1683
  const agentStatus = runnerAgentStatus(status);
1673
1684
  const activeWork = this.claims.activeWork();