agent-relay-runner 0.87.0 → 0.88.1

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.87.0",
3
+ "version": "0.88.1",
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.66"
23
+ "agent-relay-sdk": "0.2.67"
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.87.0",
4
+ "version": "0.88.1",
5
5
  "agentRelayContracts": {
6
6
  "providerPluginProtocol": 1
7
7
  }
@@ -5,17 +5,21 @@ import { DEFAULT_PROVIDER_QUOTA_CONFIG, normalizeProviderQuotaConfig, resolveCla
5
5
 
6
6
  const PASSIVE_QUOTA_CONFIG_REFRESH_MS = 60_000;
7
7
  const PASSIVE_QUOTA_SAMPLE_STALE_MS = 10 * 60_000;
8
+ const PASSIVE_QUOTA_LEASE_MAX_TTL_MS = 10 * 60_000;
9
+ const PASSIVE_QUOTA_LEASE_PADDING_MS = 60_000;
8
10
 
9
11
  interface ClaudeQuotaHarvestOptions {
10
12
  agentId: string;
11
13
  provider: string;
12
- http: () => Pick<RelayHttpClient, "getProviderQuotaConfig" | "upsertProviderQuota">;
14
+ http: () => Pick<RelayHttpClient, "acquireProviderQuotaPublisherLease" | "getProviderQuotaConfig" | "upsertProviderQuota">;
13
15
  }
14
16
 
15
17
  export class ClaudeQuotaHarvest {
16
18
  private config = { ...DEFAULT_PROVIDER_QUOTA_CONFIG };
17
19
  private configRefreshAt = 0;
18
20
  private lastReportAt?: number;
21
+ private lease?: { accountKey: string; leaseToken: string; expiresAt: number };
22
+ private nextLeaseAttemptAt?: number;
19
23
 
20
24
  constructor(private readonly options: ClaudeQuotaHarvestOptions) {}
21
25
 
@@ -30,6 +34,7 @@ export class ClaudeQuotaHarvest {
30
34
  if (this.lastReportAt !== undefined && now - this.lastReportAt < config.pollIntervalMs) return;
31
35
  const identity = await resolveClaudeStatuslineQuotaIdentity({ env: process.env });
32
36
  if (!identity) return;
37
+ if (!await this.ensurePublisherLease(identity.accountKey, config.pollIntervalMs, now)) return;
33
38
  await this.options.http().upsertProviderQuota({
34
39
  provider: "claude",
35
40
  accountKey: identity.accountKey,
@@ -55,6 +60,27 @@ export class ClaudeQuotaHarvest {
55
60
  }
56
61
  return this.config;
57
62
  }
63
+
64
+ private async ensurePublisherLease(accountKey: string, pollIntervalMs: number, now: number): Promise<boolean> {
65
+ if (this.lease?.accountKey === accountKey && this.lease.expiresAt > now) return true;
66
+ if (this.nextLeaseAttemptAt !== undefined && now < this.nextLeaseAttemptAt) return false;
67
+ const leaseToken = this.lease?.accountKey === accountKey ? this.lease.leaseToken : undefined;
68
+ const result = await this.options.http().acquireProviderQuotaPublisherLease({
69
+ provider: "claude",
70
+ accountKey,
71
+ sourceAgentId: this.options.agentId,
72
+ ...(leaseToken ? { leaseToken } : {}),
73
+ ttlMs: Math.min(PASSIVE_QUOTA_LEASE_MAX_TTL_MS, pollIntervalMs + PASSIVE_QUOTA_LEASE_PADDING_MS),
74
+ });
75
+ if (!result.acquired || !result.lease) {
76
+ this.lease = undefined;
77
+ this.nextLeaseAttemptAt = now + Math.min(result.retryAfterMs ?? pollIntervalMs, pollIntervalMs);
78
+ return false;
79
+ }
80
+ this.lease = { accountKey, leaseToken: result.lease.leaseToken, expiresAt: result.lease.expiresAt };
81
+ this.nextLeaseAttemptAt = undefined;
82
+ return true;
83
+ }
58
84
  }
59
85
 
60
86
  function freshQuotaFromProbeMetrics(metrics: NonNullable<ReturnType<typeof readRunnerContextProbeState>>, now: number): QuotaState | undefined {