@elisym/cli 0.17.1 → 0.17.2

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/dist/index.js CHANGED
@@ -2035,8 +2035,10 @@ function resolveHealthPair(skill) {
2035
2035
  return null;
2036
2036
  }
2037
2037
  var RATE_LIMIT_WINDOW_MS = 10 * 60 * 1e3;
2038
- var MAX_JOBS_PER_CUSTOMER = 20;
2039
- var GLOBAL_MAX_JOBS_PER_WINDOW = 200;
2038
+ var FREE_MAX_JOBS_PER_CUSTOMER = 20;
2039
+ var FREE_GLOBAL_MAX_JOBS_PER_WINDOW = 200;
2040
+ var PAID_MAX_JOBS_PER_CUSTOMER = 200;
2041
+ var PAID_GLOBAL_MAX_JOBS_PER_WINDOW = 2e3;
2040
2042
  var MAX_TRACKED_CUSTOMERS = 1e3;
2041
2043
  var GLOBAL_LIMITER_KEY = "__global__";
2042
2044
  var AgentRuntime = class {
@@ -2060,16 +2062,32 @@ var AgentRuntime = class {
2060
2062
  recoveryInterval = null;
2061
2063
  gcInterval = null;
2062
2064
  stopped = false;
2063
- /** Per-customer sliding-window rate limiter (keyed on customer pubkey). */
2064
- customerLimiter = createSlidingWindowLimiter({
2065
+ /** Per-customer sliding-window rate limiter for free skills. */
2066
+ freeCustomerLimiter = createSlidingWindowLimiter({
2065
2067
  windowMs: RATE_LIMIT_WINDOW_MS,
2066
- maxPerWindow: MAX_JOBS_PER_CUSTOMER,
2068
+ maxPerWindow: FREE_MAX_JOBS_PER_CUSTOMER,
2067
2069
  maxKeys: MAX_TRACKED_CUSTOMERS
2068
2070
  });
2069
- /** Global sliding-window rate limiter (Sybil protection). */
2070
- globalLimiter = createSlidingWindowLimiter({
2071
+ /** Global sliding-window rate limiter for free skills (Sybil protection). */
2072
+ freeGlobalLimiter = createSlidingWindowLimiter({
2071
2073
  windowMs: RATE_LIMIT_WINDOW_MS,
2072
- maxPerWindow: GLOBAL_MAX_JOBS_PER_WINDOW,
2074
+ maxPerWindow: FREE_GLOBAL_MAX_JOBS_PER_WINDOW,
2075
+ maxKeys: 1
2076
+ });
2077
+ /**
2078
+ * Per-customer sliding-window limiter for paid skills (10x looser than free).
2079
+ * Payment is the primary economic deterrent; this cap exists to bound the
2080
+ * "claim paid skill but never pay" queue-spam vector.
2081
+ */
2082
+ paidCustomerLimiter = createSlidingWindowLimiter({
2083
+ windowMs: RATE_LIMIT_WINDOW_MS,
2084
+ maxPerWindow: PAID_MAX_JOBS_PER_CUSTOMER,
2085
+ maxKeys: MAX_TRACKED_CUSTOMERS
2086
+ });
2087
+ /** Global sliding-window limiter for paid skills (Sybil protection, 10x free). */
2088
+ paidGlobalLimiter = createSlidingWindowLimiter({
2089
+ windowMs: RATE_LIMIT_WINDOW_MS,
2090
+ maxPerWindow: PAID_GLOBAL_MAX_JOBS_PER_WINDOW,
2073
2091
  maxKeys: 1
2074
2092
  });
2075
2093
  /**
@@ -2247,17 +2265,20 @@ var AgentRuntime = class {
2247
2265
  });
2248
2266
  return;
2249
2267
  }
2250
- if (!this.customerLimiter.peek(job.customerId).allowed) {
2268
+ const matched = this.skills.route(job.tags);
2269
+ const isPaid = matched ? matched.priceSubunits > 0 : false;
2270
+ const customerLimiter = isPaid ? this.paidCustomerLimiter : this.freeCustomerLimiter;
2271
+ const globalLimiter = isPaid ? this.paidGlobalLimiter : this.freeGlobalLimiter;
2272
+ if (!customerLimiter.peek(job.customerId).allowed) {
2251
2273
  this.transport.sendFeedback(job, { type: "error", message: "Rate limited, try again later" }).catch(() => {
2252
2274
  });
2253
2275
  return;
2254
2276
  }
2255
- if (!this.globalLimiter.peek(GLOBAL_LIMITER_KEY).allowed) {
2277
+ if (!globalLimiter.peek(GLOBAL_LIMITER_KEY).allowed) {
2256
2278
  this.transport.sendFeedback(job, { type: "error", message: "Server busy, try again later" }).catch(() => {
2257
2279
  });
2258
2280
  return;
2259
2281
  }
2260
- const matched = this.skills.route(job.tags);
2261
2282
  const isFreeLlm = matched?.mode === "llm" && matched.priceSubunits === 0;
2262
2283
  let perCustomerLimiter;
2263
2284
  let perSkillKey;
@@ -2278,8 +2299,8 @@ var AgentRuntime = class {
2278
2299
  return;
2279
2300
  }
2280
2301
  }
2281
- this.customerLimiter.check(job.customerId);
2282
- this.globalLimiter.check(GLOBAL_LIMITER_KEY);
2302
+ customerLimiter.check(job.customerId);
2303
+ globalLimiter.check(GLOBAL_LIMITER_KEY);
2283
2304
  if (isFreeLlm && perCustomerLimiter && perSkillKey) {
2284
2305
  this.freeLlmLimiters.globalLimiter.check(FREE_LLM_GLOBAL_KEY);
2285
2306
  perCustomerLimiter.check(perSkillKey);
@@ -2313,8 +2334,10 @@ var AgentRuntime = class {
2313
2334
  }
2314
2335
  /** Drop expired hits from every sliding-window limiter. */
2315
2336
  cleanupRateLimits() {
2316
- this.customerLimiter.prune();
2317
- this.globalLimiter.prune();
2337
+ this.freeCustomerLimiter.prune();
2338
+ this.freeGlobalLimiter.prune();
2339
+ this.paidCustomerLimiter.prune();
2340
+ this.paidGlobalLimiter.prune();
2318
2341
  this.freeLlmLimiters.globalLimiter.prune();
2319
2342
  this.freeLlmLimiters.prunePerCustomer();
2320
2343
  }