athena-agent-launcher 0.3.3 → 0.3.4

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.
@@ -37,11 +37,12 @@ const TURN_TIMEOUT_MS = 120_000; // hard cap on a single turn
37
37
  const SKEW_MS = 60_000; // M2: max clock skew for the HMAC timestamp
38
38
  const REPLAY_TTL_MS = 120_000; // M2: nonce cache window (> skew)
39
39
  const DEFAULT_RATE_PER_MIN = 30; // M6: token-bucket refill
40
- const DEFAULT_MAX_CONCURRENCY = 1; // M6: in-flight cap (pilot = 1)
40
+ const DEFAULT_MAX_CONCURRENCY = 1; // M6: in-flight cap (pilot = 1) — load-bearing for arm custody, do NOT raise
41
+ const BUSY_RETRY_AFTER_MS = 2000; // DAE-16: hint the poller waits before retrying a busy container
41
42
 
42
- function sendJson(res, status, obj) {
43
+ function sendJson(res, status, obj, headers) {
43
44
  const body = JSON.stringify(obj);
44
- res.writeHead(status, { "content-type": "application/json; charset=utf-8" });
45
+ res.writeHead(status, { "content-type": "application/json; charset=utf-8", ...(headers || {}) });
45
46
  res.end(body);
46
47
  }
47
48
 
@@ -292,12 +293,32 @@ export async function startHostedGateway({ hermesBin, env, hermesHome, hostedGat
292
293
  // M6 — rate limit, then hard concurrency cap. Fail closed (429), never open.
293
294
  if (!takeToken()) {
294
295
  logEvent({ event: "rate_limited", request_id: requestId, status: 429 });
295
- sendJson(res, 429, { error: "rate limited" });
296
+ sendJson(
297
+ res,
298
+ 429,
299
+ { status: "rate_limited", reason: "rate_limited", message: "Too many requests — try again shortly.", retry_after_ms: BUSY_RETRY_AFTER_MS },
300
+ { "retry-after": String(Math.ceil(BUSY_RETRY_AFTER_MS / 1000)) },
301
+ );
296
302
  return;
297
303
  }
298
304
  if (inFlight >= maxConcurrency) {
299
- logEvent({ event: "over_capacity", request_id: requestId, status: 429, in_flight: inFlight });
300
- sendJson(res, 429, { error: "busy" });
305
+ // DAE-16 (D3 container half): a turn is already in flight. max_concurrency
306
+ // stays 1 (load-bearing for arm custody never raised), so instead of
307
+ // blocking or a bare 429 we return an IMMEDIATE, TYPED busy signal the
308
+ // poller (IRIS-24) relays. Contract: HTTP 429 + Retry-After, body
309
+ // { status:"busy", reason:"turn_in_flight", message, retry_after_ms }.
310
+ logEvent({ event: "busy", request_id: requestId, status: 429, reason: "turn_in_flight", in_flight: inFlight });
311
+ sendJson(
312
+ res,
313
+ 429,
314
+ {
315
+ status: "busy",
316
+ reason: "turn_in_flight",
317
+ message: "The agent is still processing a previous message — try again shortly.",
318
+ retry_after_ms: BUSY_RETRY_AFTER_MS,
319
+ },
320
+ { "retry-after": String(Math.ceil(BUSY_RETRY_AFTER_MS / 1000)) },
321
+ );
301
322
  return;
302
323
  }
303
324
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "athena-agent-launcher",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Run an Athena-configured agent locally. Resolves runtime + bindings from the Athena control plane and spawns the correct agent binary (Anthropic SDK, OpenClaw, or Hermes).",
5
5
  "type": "module",
6
6
  "bin": {