@evident-ai/runner-cdk 3.5.2-dev.43244a2 → 3.5.2-dev.8d3aa06

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.
@@ -49818,7 +49818,7 @@ function verifyWakeSignature(rawBody, signatureHeader, secret) {
49818
49818
  return (0, import_node_crypto11.timingSafeEqual)(providedBuffer, expectedBuffer);
49819
49819
  }
49820
49820
 
49821
- // src/microvm/controller/doorbell.ts
49821
+ // src/microvm/controller/doorbell-request.ts
49822
49822
  var WAKE_EVENT_TYPES = ["agent.message_queued", "agent.wake_requested"];
49823
49823
  var SUSPEND_EVENT_TYPE = "runner.suspend_requested";
49824
49824
  var SHAPES_EVENT_TYPE = "runner.shapes_requested";
@@ -49838,7 +49838,7 @@ function nonBlankString(value) {
49838
49838
  function isWakeType(value) {
49839
49839
  return WAKE_EVENT_TYPES.includes(value);
49840
49840
  }
49841
- function parseDoorbell(rawBody) {
49841
+ function parseDoorbellRequest(rawBody) {
49842
49842
  let body;
49843
49843
  try {
49844
49844
  body = JSON.parse(rawBody);
@@ -49979,9 +49979,9 @@ function decide({
49979
49979
  action: { kind: action }
49980
49980
  };
49981
49981
  }
49982
- function clientTokenFor(doorbell) {
49983
- const generation = doorbell.microvmId ?? doorbell.occurredAt;
49984
- return (0, import_node_crypto12.createHash)("sha256").update(`${doorbell.runnerId}:${generation}`).digest("hex");
49982
+ function clientTokenFor(doorbellRequest) {
49983
+ const generation = doorbellRequest.microvmId ?? doorbellRequest.occurredAt;
49984
+ return (0, import_node_crypto12.createHash)("sha256").update(`${doorbellRequest.runnerId}:${generation}`).digest("hex");
49985
49985
  }
49986
49986
  function parseImageVersion(value) {
49987
49987
  const parts = value.trim().split(".");
@@ -50001,17 +50001,17 @@ function compareImageVersions(a7, b7) {
50001
50001
  }
50002
50002
  return 0;
50003
50003
  }
50004
- async function shouldRecreateForNewerImage(doorbell, shape, runningVersion, microvm) {
50004
+ async function shouldRecreateForNewerImage(doorbellRequest, shape, runningVersion, microvm) {
50005
50005
  if (runningVersion === void 0) {
50006
50006
  console.warn(
50007
- `[doorbell] GetMicrovm reported no imageVersion for runner ${doorbell.runnerId}; resuming`
50007
+ `[doorbell] GetMicrovm reported no imageVersion for runner ${doorbellRequest.runnerId}; resuming`
50008
50008
  );
50009
50009
  return false;
50010
50010
  }
50011
50011
  const running = parseImageVersion(runningVersion);
50012
50012
  if (running === void 0) {
50013
50013
  console.warn(
50014
- `[doorbell] unparseable running imageVersion "${runningVersion}" for runner ${doorbell.runnerId}; resuming`
50014
+ `[doorbell] unparseable running imageVersion "${runningVersion}" for runner ${doorbellRequest.runnerId}; resuming`
50015
50015
  );
50016
50016
  return false;
50017
50017
  }
@@ -50020,14 +50020,14 @@ async function shouldRecreateForNewerImage(doorbell, shape, runningVersion, micr
50020
50020
  latestVersion = await microvm.latestImageVersion(shape.imageArn);
50021
50021
  } catch (error3) {
50022
50022
  console.warn(
50023
- `[doorbell] GetMicrovmImage failed for runner ${doorbell.runnerId}; resuming on the running image ${runningVersion}: ${error3 instanceof Error ? error3.message : String(error3)}`
50023
+ `[doorbell] GetMicrovmImage failed for runner ${doorbellRequest.runnerId}; resuming on the running image ${runningVersion}: ${error3 instanceof Error ? error3.message : String(error3)}`
50024
50024
  );
50025
50025
  return false;
50026
50026
  }
50027
50027
  const latest = latestVersion === void 0 ? void 0 : parseImageVersion(latestVersion);
50028
50028
  if (latest === void 0) {
50029
50029
  console.warn(
50030
- `[doorbell] no comparable latest image version (${latestVersion ?? "none"}) for runner ${doorbell.runnerId}; resuming on the running image ${runningVersion}`
50030
+ `[doorbell] no comparable latest image version (${latestVersion ?? "none"}) for runner ${doorbellRequest.runnerId}; resuming on the running image ${runningVersion}`
50031
50031
  );
50032
50032
  return false;
50033
50033
  }
@@ -50049,7 +50049,7 @@ async function handleDoorbell({
50049
50049
  reason: REASON.invalidSignature
50050
50050
  });
50051
50051
  }
50052
- const parsed = parseDoorbell(rawBody);
50052
+ const parsed = parseDoorbellRequest(rawBody);
50053
50053
  if (!parsed.ok) {
50054
50054
  return decide({
50055
50055
  statusCode: 400,
@@ -50057,9 +50057,9 @@ async function handleDoorbell({
50057
50057
  reason: parsed.reason
50058
50058
  });
50059
50059
  }
50060
- const doorbell = parsed.doorbell;
50060
+ const doorbellRequest = parsed.doorbell;
50061
50061
  const timing = { sleep: sleep4, random };
50062
- if (doorbell.type === SHAPES_EVENT_TYPE) {
50062
+ if (doorbellRequest.type === SHAPES_EVENT_TYPE) {
50063
50063
  return decide({
50064
50064
  statusCode: 200,
50065
50065
  action: "describe",
@@ -50067,43 +50067,43 @@ async function handleDoorbell({
50067
50067
  shapes: shapes.advertise()
50068
50068
  });
50069
50069
  }
50070
- if (doorbell.type !== "runner.suspend_requested") {
50071
- const resolvedShape = shapes.resolve(doorbell.shape);
50070
+ if (doorbellRequest.type !== "runner.suspend_requested") {
50071
+ const resolvedShape = shapes.resolve(doorbellRequest.shape);
50072
50072
  if (resolvedShape === void 0) {
50073
50073
  return decide({
50074
50074
  statusCode: 400,
50075
50075
  action: "rejected",
50076
50076
  reason: REASON.unknownShape,
50077
- runnerId: doorbell.runnerId,
50078
- microvmId: doorbell.microvmId
50077
+ runnerId: doorbellRequest.runnerId,
50078
+ microvmId: doorbellRequest.microvmId
50079
50079
  });
50080
50080
  }
50081
- return handleWakeDoorbell(doorbell, resolvedShape, microvm, timing);
50081
+ return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing);
50082
50082
  }
50083
- return suspendMicrovm(doorbell, microvm, timing);
50083
+ return suspendMicrovm(doorbellRequest, microvm, timing);
50084
50084
  }
50085
- async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
50086
- if (doorbell.microvmId === void 0) {
50087
- return runMicrovm(doorbell, shape, microvm, timing, false, REASON.noMicrovmId);
50085
+ async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
50086
+ if (doorbellRequest.microvmId === void 0) {
50087
+ return runMicrovm(doorbellRequest, shape, microvm, timing, false, REASON.noMicrovmId);
50088
50088
  }
50089
50089
  let described;
50090
50090
  let polled = false;
50091
50091
  try {
50092
- described = await microvm.describe(doorbell.microvmId);
50092
+ described = await microvm.describe(doorbellRequest.microvmId);
50093
50093
  if (described.state === "SUSPENDING") {
50094
- described = await pollWhileSuspending(doorbell.microvmId, microvm, timing.sleep);
50094
+ described = await pollWhileSuspending(doorbellRequest.microvmId, microvm, timing.sleep);
50095
50095
  polled = true;
50096
50096
  }
50097
50097
  } catch (error3) {
50098
50098
  console.error(
50099
- `[doorbell] GetMicrovm failed for runner ${doorbell.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50099
+ `[doorbell] GetMicrovm failed for runner ${doorbellRequest.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50100
50100
  );
50101
50101
  return decide({
50102
50102
  statusCode: 500,
50103
50103
  action: "none",
50104
50104
  reason: REASON.getStateFailed,
50105
- runnerId: doorbell.runnerId,
50106
- microvmId: doorbell.microvmId
50105
+ runnerId: doorbellRequest.runnerId,
50106
+ microvmId: doorbellRequest.microvmId
50107
50107
  });
50108
50108
  }
50109
50109
  const state3 = described.state;
@@ -50113,8 +50113,8 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
50113
50113
  action: "none",
50114
50114
  reason: REASON.suspendingPollExhausted,
50115
50115
  state: state3,
50116
- runnerId: doorbell.runnerId,
50117
- microvmId: doorbell.microvmId,
50116
+ runnerId: doorbellRequest.runnerId,
50117
+ microvmId: doorbellRequest.microvmId,
50118
50118
  polled
50119
50119
  });
50120
50120
  }
@@ -50126,16 +50126,16 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
50126
50126
  action: "none",
50127
50127
  reason: state3 === "RUNNING" ? REASON.alreadyRunning : REASON.alreadyStarting,
50128
50128
  state: state3,
50129
- runnerId: doorbell.runnerId,
50130
- microvmId: doorbell.microvmId,
50129
+ runnerId: doorbellRequest.runnerId,
50130
+ microvmId: doorbellRequest.microvmId,
50131
50131
  polled,
50132
50132
  startedAt: described.startedAt,
50133
50133
  imageVersion: described.imageVersion
50134
50134
  });
50135
50135
  case "SUSPENDED":
50136
- if (doorbell.recreateOnOutdatedImage === true && await shouldRecreateForNewerImage(doorbell, shape, described.imageVersion, microvm)) {
50136
+ if (doorbellRequest.recreateOnOutdatedImage === true && await shouldRecreateForNewerImage(doorbellRequest, shape, described.imageVersion, microvm)) {
50137
50137
  return runMicrovm(
50138
- doorbell,
50138
+ doorbellRequest,
50139
50139
  shape,
50140
50140
  microvm,
50141
50141
  timing,
@@ -50145,8 +50145,8 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
50145
50145
  );
50146
50146
  }
50147
50147
  return resumeMicrovm(
50148
- doorbell,
50149
- doorbell.microvmId,
50148
+ doorbellRequest,
50149
+ doorbellRequest.microvmId,
50150
50150
  shape,
50151
50151
  microvm,
50152
50152
  timing,
@@ -50156,7 +50156,7 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
50156
50156
  );
50157
50157
  default:
50158
50158
  return runMicrovm(
50159
- doorbell,
50159
+ doorbellRequest,
50160
50160
  shape,
50161
50161
  microvm,
50162
50162
  timing,
@@ -50182,14 +50182,14 @@ function isClientTokenParameterMismatch(error3) {
50182
50182
  const message = typeof e7.message === "string" ? e7.message.toLowerCase() : "";
50183
50183
  return message.includes("clienttoken") && message.includes("different request parameters");
50184
50184
  }
50185
- async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, state3) {
50185
+ async function runMicrovm(doorbellRequest, shape, microvm, timing, polled, reason, state3) {
50186
50186
  let started;
50187
50187
  try {
50188
50188
  started = await withThrottleRetry(
50189
50189
  () => microvm.run({
50190
50190
  imageIdentifier: shape.imageArn,
50191
- runHookPayload: doorbell.runHookPayload,
50192
- clientToken: clientTokenFor(doorbell)
50191
+ runHookPayload: doorbellRequest.runHookPayload,
50192
+ clientToken: clientTokenFor(doorbellRequest)
50193
50193
  }),
50194
50194
  timing
50195
50195
  );
@@ -50198,26 +50198,26 @@ async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, stat
50198
50198
  const name = error3 instanceof Error ? error3.name : "unknown";
50199
50199
  const message = error3 instanceof Error ? error3.message : String(error3);
50200
50200
  console.warn(
50201
- `[doorbell] RunMicrovm clientToken already used for runner ${doorbell.runnerId}: ${name}: ${message}`
50201
+ `[doorbell] RunMicrovm clientToken already used for runner ${doorbellRequest.runnerId}: ${name}: ${message}`
50202
50202
  );
50203
50203
  return decide({
50204
50204
  statusCode: 200,
50205
50205
  action: "run",
50206
50206
  reason: REASON.runAlreadyStartedForToken,
50207
50207
  state: state3,
50208
- runnerId: doorbell.runnerId,
50208
+ runnerId: doorbellRequest.runnerId,
50209
50209
  polled
50210
50210
  });
50211
50211
  }
50212
50212
  console.error(
50213
- `[doorbell] RunMicrovm failed for runner ${doorbell.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50213
+ `[doorbell] RunMicrovm failed for runner ${doorbellRequest.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50214
50214
  );
50215
50215
  return decide({
50216
50216
  statusCode: 500,
50217
50217
  action: "run",
50218
50218
  reason: REASON.runFailed,
50219
50219
  state: state3,
50220
- runnerId: doorbell.runnerId,
50220
+ runnerId: doorbellRequest.runnerId,
50221
50221
  polled
50222
50222
  });
50223
50223
  }
@@ -50226,22 +50226,22 @@ async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, stat
50226
50226
  action: "run",
50227
50227
  reason,
50228
50228
  state: state3,
50229
- runnerId: doorbell.runnerId,
50229
+ runnerId: doorbellRequest.runnerId,
50230
50230
  microvmId: started.microvmId,
50231
50231
  polled,
50232
50232
  startedAt: started.startedAt,
50233
50233
  imageVersion: started.imageVersion
50234
50234
  });
50235
50235
  }
50236
- async function resumeMicrovm(doorbell, microvmId, shape, microvm, timing, polled, startedAt, imageVersion) {
50236
+ async function resumeMicrovm(doorbellRequest, microvmId, shape, microvm, timing, polled, startedAt, imageVersion) {
50237
50237
  try {
50238
50238
  await withThrottleRetry(() => microvm.resume(microvmId), timing);
50239
50239
  } catch (error3) {
50240
50240
  console.error(
50241
- `[doorbell] ResumeMicrovm failed for runner ${doorbell.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50241
+ `[doorbell] ResumeMicrovm failed for runner ${doorbellRequest.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50242
50242
  );
50243
50243
  return runMicrovm(
50244
- doorbell,
50244
+ doorbellRequest,
50245
50245
  shape,
50246
50246
  microvm,
50247
50247
  timing,
@@ -50255,21 +50255,21 @@ async function resumeMicrovm(doorbell, microvmId, shape, microvm, timing, polled
50255
50255
  action: "resume",
50256
50256
  reason: REASON.resumed,
50257
50257
  state: "SUSPENDED",
50258
- runnerId: doorbell.runnerId,
50258
+ runnerId: doorbellRequest.runnerId,
50259
50259
  microvmId,
50260
50260
  polled,
50261
50261
  startedAt,
50262
50262
  imageVersion
50263
50263
  });
50264
50264
  }
50265
- async function suspendMicrovm(doorbell, microvm, timing) {
50266
- const microvmId = doorbell.microvmId;
50265
+ async function suspendMicrovm(doorbellRequest, microvm, timing) {
50266
+ const microvmId = doorbellRequest.microvmId;
50267
50267
  if (microvmId === void 0) {
50268
50268
  return decide({
50269
50269
  statusCode: 200,
50270
50270
  action: "none",
50271
50271
  reason: REASON.suspendWithoutMicrovmId,
50272
- runnerId: doorbell.runnerId
50272
+ runnerId: doorbellRequest.runnerId
50273
50273
  });
50274
50274
  }
50275
50275
  let state3;
@@ -50277,13 +50277,13 @@ async function suspendMicrovm(doorbell, microvm, timing) {
50277
50277
  ({ state: state3 } = await microvm.describe(microvmId));
50278
50278
  } catch (error3) {
50279
50279
  console.error(
50280
- `[doorbell] GetMicrovm failed for runner ${doorbell.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50280
+ `[doorbell] GetMicrovm failed for runner ${doorbellRequest.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50281
50281
  );
50282
50282
  return decide({
50283
50283
  statusCode: 500,
50284
50284
  action: "none",
50285
50285
  reason: REASON.getStateFailed,
50286
- runnerId: doorbell.runnerId,
50286
+ runnerId: doorbellRequest.runnerId,
50287
50287
  microvmId
50288
50288
  });
50289
50289
  }
@@ -50293,7 +50293,7 @@ async function suspendMicrovm(doorbell, microvm, timing) {
50293
50293
  action: "none",
50294
50294
  reason: REASON.suspendAlreadyGone,
50295
50295
  state: state3,
50296
- runnerId: doorbell.runnerId,
50296
+ runnerId: doorbellRequest.runnerId,
50297
50297
  microvmId
50298
50298
  });
50299
50299
  }
@@ -50301,14 +50301,14 @@ async function suspendMicrovm(doorbell, microvm, timing) {
50301
50301
  await withThrottleRetry(() => microvm.suspend(microvmId), timing);
50302
50302
  } catch (error3) {
50303
50303
  console.error(
50304
- `[doorbell] SuspendMicrovm failed for runner ${doorbell.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50304
+ `[doorbell] SuspendMicrovm failed for runner ${doorbellRequest.runnerId}: ${error3 instanceof Error ? error3.message : String(error3)}`
50305
50305
  );
50306
50306
  return decide({
50307
50307
  statusCode: 500,
50308
50308
  action: "suspend",
50309
50309
  reason: REASON.suspendFailed,
50310
50310
  state: state3,
50311
- runnerId: doorbell.runnerId,
50311
+ runnerId: doorbellRequest.runnerId,
50312
50312
  microvmId
50313
50313
  });
50314
50314
  }
@@ -50317,7 +50317,7 @@ async function suspendMicrovm(doorbell, microvm, timing) {
50317
50317
  action: "suspend",
50318
50318
  reason: REASON.suspended,
50319
50319
  state: state3,
50320
- runnerId: doorbell.runnerId,
50320
+ runnerId: doorbellRequest.runnerId,
50321
50321
  microvmId
50322
50322
  });
50323
50323
  }
@@ -50468,12 +50468,7 @@ function createRuntimeMicrovm(executionRoleArn) {
50468
50468
  // No `idlePolicy` (AC5, #732) — deliberately, not an oversight.
50469
50469
  // `maxIdleDurationSeconds` measures INBOUND endpoint traffic only; our
50470
50470
  // runner is outbound-only (it dials the Cloudflare relay), so AWS sees
50471
- // an idle endpoint no matter how busy the agent is. Phase 0 measured
50472
- // this directly: a VM with `maxIdleDurationSeconds=60` and zero inbound
50473
- // traffic was suspended after 71 s while its guest process was alive
50474
- // and working (docs/spikes/lambda-microvms-phase0/README.md). AWS's own
50475
- // Claude-agents guidance recommending `maxIdleDurationSeconds: 120`
50476
- // targets VMs reached inbound and does not apply here. Idle is instead
50471
+ // an idle endpoint no matter how busy the agent is. Idle is instead
50477
50472
  // decided IN the VM by `evident run --idle-timeout`
50478
50473
  // (packages/runner-cdk/microvm-image/hooks/common.sh's `IDLE_TIMEOUT_SECONDS`), whose
50479
50474
  // clean exit is what drives the controller's own `suspend()` below via
@@ -39,6 +39,7 @@ const constructs_1 = require("constructs");
39
39
  const ec2 = __importStar(require("aws-cdk-lib/aws-ec2"));
40
40
  const ecs = __importStar(require("aws-cdk-lib/aws-ecs"));
41
41
  const iam = __importStar(require("aws-cdk-lib/aws-iam"));
42
+ const constants_1 = require("./microvm/constants");
42
43
  const construct_1 = require("./waker/construct");
43
44
  /** Current fixed value of `resourcePrefix`, kept as the default so an adopter
44
45
  * omitting the prop reproduces today's physical names exactly. */
@@ -111,15 +112,7 @@ class EvidentScaleToZeroConstruct extends constructs_1.Construct {
111
112
  GIT_BRANCH: gitBranch ?? 'main',
112
113
  // Scale-to-zero self-stop inputs (the entrypoint uses these to scale to 0).
113
114
  EVIDENT_IDLE_TIMEOUT_SECONDS: String(idleTimeoutSeconds),
114
- // Auto-cleanup (issue #190): `evident run` reads this directly and, once a
115
- // retention rule is set, sweeps OpenCode sessions idle longer than the
116
- // window (protected/active sessions are never touched). Tightened from 7d
117
- // to 24h per #537: at 7d, opencode.db was observed growing ~11x (77 MB ->
118
- // 849 MB) in ~24h, so 7d was far too permissive at the observed growth
119
- // rate. 24h is the tighter mitigation that came out of that (see also the
120
- // OPENCODE_VERSION pin above). Sweep runs on the default 1h interval and
121
- // never touches a protected/active session.
122
- EVIDENT_SESSION_CLEANUP_MAX_AGE: '24h',
115
+ EVIDENT_SESSION_CLEANUP_MAX_AGE: constants_1.SESSION_CLEANUP_MAX_AGE,
123
116
  CLUSTER: cluster.clusterName,
124
117
  SERVICE: serviceName,
125
118
  EVIDENT_SELFSTOP_ROLE_ARN: selfStopRole.roleArn,
@@ -5,3 +5,5 @@ export declare const RUN_HOOK_PAYLOAD_MAX_BYTES = 16384;
5
5
  export declare const SUSPENDING_POLL_ATTEMPTS = 4;
6
6
  export declare const SUSPENDING_POLL_INTERVAL_MS = 500;
7
7
  export declare const MICROVM_MAX_RUN_SECONDS = 28800;
8
+ export declare const SESSION_CLEANUP_MAX_AGE = "24h";
9
+ export declare const DOORBELL_SECRET_KEY = "DOORBELL_SECRET";
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
- // Shared literals for the MicroVM controller and for the image it launches.
2
+ // Shared literals for the MicroVM controller, its image, and the Fargate runner.
3
3
  // Every module imports from here rather than restating a value that must match
4
4
  // across them. The image template pins matching copies, guarded by
5
5
  // `microvm/image/dockerfile.test.ts`.
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.MICROVM_MAX_RUN_SECONDS = exports.SUSPENDING_POLL_INTERVAL_MS = exports.SUSPENDING_POLL_ATTEMPTS = exports.RUN_HOOK_PAYLOAD_MAX_BYTES = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_DIR = exports.HOOKS_PORT = void 0;
7
+ exports.DOORBELL_SECRET_KEY = exports.SESSION_CLEANUP_MAX_AGE = exports.MICROVM_MAX_RUN_SECONDS = exports.SUSPENDING_POLL_INTERVAL_MS = exports.SUSPENDING_POLL_ATTEMPTS = exports.RUN_HOOK_PAYLOAD_MAX_BYTES = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_DIR = exports.HOOKS_PORT = void 0;
8
8
  // The port the image's hook server binds, baked into the published Dockerfile
9
9
  // (`ENV HOOKS_PORT`) and passed to the construct as `hooksPort`. Exported from
10
10
  // the package index because a consumer building the published image context
@@ -32,3 +32,12 @@ exports.SUSPENDING_POLL_INTERVAL_MS = 500;
32
32
  // longer than any VM can possibly still be running, no VM started before the
33
33
  // deactivation can outlive it. The two MUST move together.
34
34
  exports.MICROVM_MAX_RUN_SECONDS = 28800;
35
+ // Auto-cleanup (issue #190): `evident run` reads this directly from the Fargate
36
+ // task and MicroVM image. Setting a retention rule makes it sweep OpenCode
37
+ // sessions idle longer than 24h; protected/active sessions are never touched.
38
+ // The 24h window rather than 7d keeps the session database bounded at the growth
39
+ // rate observed in #537. The sweep runs on the default 1h interval.
40
+ exports.SESSION_CLEANUP_MAX_AGE = '24h';
41
+ // The JSON field inside the doorbell secret is shared by the Lambdas that name
42
+ // it and by whatever produces the secret; this is never the secret value.
43
+ exports.DOORBELL_SECRET_KEY = 'DOORBELL_SECRET';
@@ -40,14 +40,12 @@ const constructs_1 = require("constructs");
40
40
  const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
41
41
  const s3 = __importStar(require("aws-cdk-lib/aws-s3"));
42
42
  const lambda_microvm_cdk_1 = require("@evident-ai/lambda-microvm-cdk");
43
+ const constants_1 = require("./constants");
43
44
  const shapes_1 = require("./shapes");
44
45
  const construct_1 = require("./image-version-reporter/construct");
45
46
  // Image hooks build the snapshot, so they get minutes where the runtime hooks
46
47
  // get AWS's 60 s.
47
48
  const IMAGE_HOOK_TIMEOUT_SECONDS = 600;
48
- // The field inside the doorbell secret, shared by this construct (which
49
- // names it for the controller) and whatever produced `props.doorbellSecret`.
50
- const DOORBELL_SECRET_KEY = 'DOORBELL_SECRET';
51
49
  /**
52
50
  * The customer-account half of the per-session runner (#558): the MicroVM
53
51
  * image and the roles it builds and runs as, plus the stateless controller
@@ -127,10 +125,8 @@ class EvidentMicrovmConstruct extends constructs_1.Construct {
127
125
  // ("Environment variable key 'AWS_REGION' is reserved", 400), which is
128
126
  // also why the synchroniser's S3 client does not need it set — the
129
127
  // MicroVM runtime supplies the region itself.
130
- // Read by `evident run` itself (not the hooks), the same 24h window ECS
131
- // already bakes in for its own runners (evident-scale-to-zero-construct.ts:191).
132
128
  // Safe to bake: identical for every VM from this image version.
133
- EVIDENT_SESSION_CLEANUP_MAX_AGE: '24h',
129
+ EVIDENT_SESSION_CLEANUP_MAX_AGE: constants_1.SESSION_CLEANUP_MAX_AGE,
134
130
  ...(props.runnerOpencodeConfigPath
135
131
  ? { RUNNER_OPENCODE_CONFIG: props.runnerOpencodeConfigPath }
136
132
  : {}),
@@ -240,7 +236,7 @@ class EvidentMicrovmConstruct extends constructs_1.Construct {
240
236
  // Secrets Manager at runtime, so the key is not exposed to anyone with
241
237
  // lambda:GetFunctionConfiguration.
242
238
  DOORBELL_SECRET_ARN: props.doorbellSecret.secretArn,
243
- DOORBELL_SECRET_KEY: DOORBELL_SECRET_KEY,
239
+ DOORBELL_SECRET_KEY: constants_1.DOORBELL_SECRET_KEY,
244
240
  MICROVM_SHAPES: shapeCatalogueJson,
245
241
  // The role every shape's MicroVM shares (D3) — still one role, still
246
242
  // this same expression, now documented as shared rather than singular.
@@ -27,12 +27,12 @@ declare const WAKE_EVENT_TYPES: readonly ["agent.message_queued", "agent.wake_re
27
27
  declare const SUSPEND_EVENT_TYPE = "runner.suspend_requested";
28
28
  export declare const SHAPES_EVENT_TYPE = "runner.shapes_requested";
29
29
  type WakeEventType = (typeof WAKE_EVENT_TYPES)[number];
30
- type DoorbellFields = {
30
+ type DoorbellRequestFields = {
31
31
  runnerId: string;
32
32
  occurredAt: string;
33
33
  microvmId?: string;
34
34
  };
35
- export type WakeDoorbell = DoorbellFields & {
35
+ export type WakeDoorbellRequest = DoorbellRequestFields & {
36
36
  type: WakeEventType;
37
37
  runHookPayload: string;
38
38
  /**
@@ -46,7 +46,7 @@ export type WakeDoorbell = DoorbellFields & {
46
46
  */
47
47
  recreateOnOutdatedImage?: boolean;
48
48
  };
49
- export type Doorbell = WakeDoorbell | (DoorbellFields & {
49
+ export type DoorbellRequest = WakeDoorbellRequest | (DoorbellRequestFields & {
50
50
  type: typeof SUSPEND_EVENT_TYPE;
51
51
  }) | {
52
52
  type: typeof SHAPES_EVENT_TYPE;
@@ -67,12 +67,12 @@ export declare const DOORBELL_REJECTION: {
67
67
  readonly runPayloadTooLarge: "run_payload_too_large";
68
68
  };
69
69
  export type DoorbellRejection = (typeof DOORBELL_REJECTION)[keyof typeof DOORBELL_REJECTION];
70
- export type ParsedDoorbell = {
70
+ export type ParsedDoorbellRequest = {
71
71
  ok: true;
72
- doorbell: Doorbell;
72
+ doorbell: DoorbellRequest;
73
73
  } | {
74
74
  ok: false;
75
75
  reason: DoorbellRejection;
76
76
  };
77
- export declare function parseDoorbell(rawBody: string): ParsedDoorbell;
77
+ export declare function parseDoorbellRequest(rawBody: string): ParsedDoorbellRequest;
78
78
  export {};
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DOORBELL_REJECTION = exports.SHAPES_EVENT_TYPE = void 0;
4
- exports.parseDoorbell = parseDoorbell;
4
+ exports.parseDoorbellRequest = parseDoorbellRequest;
5
5
  const constants_1 = require("../constants");
6
6
  /**
7
7
  * The doorbell Evident POSTs to the controller's Function URL. `run_payload` is
@@ -52,7 +52,7 @@ function nonBlankString(value) {
52
52
  function isWakeType(value) {
53
53
  return WAKE_EVENT_TYPES.includes(value);
54
54
  }
55
- function parseDoorbell(rawBody) {
55
+ function parseDoorbellRequest(rawBody) {
56
56
  let body;
57
57
  try {
58
58
  body = JSON.parse(rawBody);
@@ -4,7 +4,7 @@ exports.handleDoorbell = handleDoorbell;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const sdk_1 = require("@evident/sdk");
6
6
  const constants_1 = require("../constants");
7
- const doorbell_1 = require("./doorbell");
7
+ const doorbell_request_1 = require("./doorbell-request");
8
8
  const throttle_retry_1 = require("./throttle-retry");
9
9
  const REASON = {
10
10
  invalidSignature: 'invalid_signature',
@@ -65,7 +65,7 @@ function decide({ statusCode, action, reason, state, runnerId, microvmId, starte
65
65
  }
66
66
  /**
67
67
  * `RunMicrovm`'s idempotency key. Keyed on `runner_id` plus a "generation"
68
- * marker: the dead VM's `microvm_id` on the recovery arms (`doorbell.microvmId`
68
+ * marker: the dead VM's `microvm_id` on the recovery arms (`doorbellRequest.microvmId`
69
69
  * is defined — TERMINATED/TERMINATING/not_found and the resume-failed
70
70
  * fallback), else `occurred_at` on the cold arm (no `microvm_id` yet). The id
71
71
  * advances every VM generation — `mvm-A` dies, the token keyed on it starts
@@ -92,9 +92,9 @@ function decide({ statusCode, action, reason, state, runnerId, microvmId, starte
92
92
  * that retried the same event with a different shape starts TWO concurrent
93
93
  * 8-hour VMs instead of deduping to one.
94
94
  */
95
- function clientTokenFor(doorbell) {
96
- const generation = doorbell.microvmId ?? doorbell.occurredAt;
97
- return (0, node_crypto_1.createHash)('sha256').update(`${doorbell.runnerId}:${generation}`).digest('hex');
95
+ function clientTokenFor(doorbellRequest) {
96
+ const generation = doorbellRequest.microvmId ?? doorbellRequest.occurredAt;
97
+ return (0, node_crypto_1.createHash)('sha256').update(`${doorbellRequest.runnerId}:${generation}`).digest('hex');
98
98
  }
99
99
  /**
100
100
  * MicroVM image versions are dotted decimals (`48.0`, `50.0`), so they must NOT
@@ -140,15 +140,15 @@ function compareImageVersions(a, b) {
140
140
  * unparseable all warn and return false, i.e. resume exactly as before
141
141
  * (`development-workflow.mdc`: never fail a gate on absent evidence).
142
142
  */
143
- async function shouldRecreateForNewerImage(doorbell, shape, runningVersion, microvm) {
143
+ async function shouldRecreateForNewerImage(doorbellRequest, shape, runningVersion, microvm) {
144
144
  if (runningVersion === undefined) {
145
- console.warn(`[doorbell] GetMicrovm reported no imageVersion for runner ${doorbell.runnerId}; resuming`);
145
+ console.warn(`[doorbell] GetMicrovm reported no imageVersion for runner ${doorbellRequest.runnerId}; resuming`);
146
146
  return false;
147
147
  }
148
148
  const running = parseImageVersion(runningVersion);
149
149
  if (running === undefined) {
150
150
  console.warn(`[doorbell] unparseable running imageVersion "${runningVersion}" for runner ` +
151
- `${doorbell.runnerId}; resuming`);
151
+ `${doorbellRequest.runnerId}; resuming`);
152
152
  return false;
153
153
  }
154
154
  let latestVersion;
@@ -159,14 +159,14 @@ async function shouldRecreateForNewerImage(doorbell, shape, runningVersion, micr
159
159
  latestVersion = await microvm.latestImageVersion(shape.imageArn);
160
160
  }
161
161
  catch (error) {
162
- console.warn(`[doorbell] GetMicrovmImage failed for runner ${doorbell.runnerId}; resuming on the ` +
162
+ console.warn(`[doorbell] GetMicrovmImage failed for runner ${doorbellRequest.runnerId}; resuming on the ` +
163
163
  `running image ${runningVersion}: ${error instanceof Error ? error.message : String(error)}`);
164
164
  return false;
165
165
  }
166
166
  const latest = latestVersion === undefined ? undefined : parseImageVersion(latestVersion);
167
167
  if (latest === undefined) {
168
168
  console.warn(`[doorbell] no comparable latest image version (${latestVersion ?? 'none'}) for runner ` +
169
- `${doorbell.runnerId}; resuming on the running image ${runningVersion}`);
169
+ `${doorbellRequest.runnerId}; resuming on the running image ${runningVersion}`);
170
170
  return false;
171
171
  }
172
172
  // Strictly below, not merely different: a running version ABOVE the latest
@@ -182,7 +182,7 @@ async function handleDoorbell({ rawBody, signatureHeader, doorbellSecret, shapes
182
182
  reason: REASON.invalidSignature,
183
183
  });
184
184
  }
185
- const parsed = (0, doorbell_1.parseDoorbell)(rawBody);
185
+ const parsed = (0, doorbell_request_1.parseDoorbellRequest)(rawBody);
186
186
  if (!parsed.ok) {
187
187
  return decide({
188
188
  statusCode: 400,
@@ -190,10 +190,10 @@ async function handleDoorbell({ rawBody, signatureHeader, doorbellSecret, shapes
190
190
  reason: parsed.reason,
191
191
  });
192
192
  }
193
- const doorbell = parsed.doorbell;
193
+ const doorbellRequest = parsed.doorbell;
194
194
  const timing = { sleep, random };
195
- if (doorbell.type === doorbell_1.SHAPES_EVENT_TYPE) {
196
- // A pure read of deploy-time metadata — see doorbell.ts's header comment
195
+ if (doorbellRequest.type === doorbell_request_1.SHAPES_EVENT_TYPE) {
196
+ // A pure read of deploy-time metadata — see doorbell-request.ts's header comment
197
197
  // (D2) for why replay is deliberately undefended here.
198
198
  return decide({
199
199
  statusCode: 200,
@@ -202,46 +202,46 @@ async function handleDoorbell({ rawBody, signatureHeader, doorbellSecret, shapes
202
202
  shapes: shapes.advertise(),
203
203
  });
204
204
  }
205
- // Resolve the requested shape immediately after parseDoorbell/the describe
205
+ // Resolve the requested shape immediately after parseDoorbellRequest/the describe
206
206
  // arm — BEFORE the suspend_requested branch and the whole state machine
207
207
  // (D5). Resolving lazily inside runMicrovm would return 200 and silently
208
208
  // ignore a removed shape on the RUNNING/PENDING no-op path and the
209
209
  // successful-resume path, since runMicrovm is never reached on either. A
210
210
  // suspend doorbell has no `shape` field, so nothing here runs for it.
211
- if (doorbell.type !== 'runner.suspend_requested') {
212
- const resolvedShape = shapes.resolve(doorbell.shape);
211
+ if (doorbellRequest.type !== 'runner.suspend_requested') {
212
+ const resolvedShape = shapes.resolve(doorbellRequest.shape);
213
213
  if (resolvedShape === undefined) {
214
214
  // 400, not 404/409: a redelivery of the identical body cannot fix this.
215
215
  // Never echo the requested shape name — the closed-constant rule
216
- // (doorbell.ts's DOORBELL_REJECTION) applies to every reason here too,
216
+ // (doorbell-request.ts's DOORBELL_REJECTION) applies to every reason here too,
217
217
  // and Evident persists response_body.
218
218
  return decide({
219
219
  statusCode: 400,
220
220
  action: 'rejected',
221
221
  reason: REASON.unknownShape,
222
- runnerId: doorbell.runnerId,
223
- microvmId: doorbell.microvmId,
222
+ runnerId: doorbellRequest.runnerId,
223
+ microvmId: doorbellRequest.microvmId,
224
224
  });
225
225
  }
226
- return handleWakeDoorbell(doorbell, resolvedShape, microvm, timing);
226
+ return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing);
227
227
  }
228
- return suspendMicrovm(doorbell, microvm, timing);
228
+ return suspendMicrovm(doorbellRequest, microvm, timing);
229
229
  }
230
- async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
231
- if (doorbell.microvmId === undefined) {
232
- return runMicrovm(doorbell, shape, microvm, timing, false, REASON.noMicrovmId);
230
+ async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
231
+ if (doorbellRequest.microvmId === undefined) {
232
+ return runMicrovm(doorbellRequest, shape, microvm, timing, false, REASON.noMicrovmId);
233
233
  }
234
234
  let described;
235
235
  let polled = false;
236
236
  try {
237
- described = await microvm.describe(doorbell.microvmId);
237
+ described = await microvm.describe(doorbellRequest.microvmId);
238
238
  if (described.state === 'SUSPENDING') {
239
- described = await pollWhileSuspending(doorbell.microvmId, microvm, timing.sleep);
239
+ described = await pollWhileSuspending(doorbellRequest.microvmId, microvm, timing.sleep);
240
240
  polled = true;
241
241
  }
242
242
  }
243
243
  catch (error) {
244
- console.error(`[doorbell] GetMicrovm failed for runner ${doorbell.runnerId}: ` +
244
+ console.error(`[doorbell] GetMicrovm failed for runner ${doorbellRequest.runnerId}: ` +
245
245
  `${error instanceof Error ? error.message : String(error)}`);
246
246
  // `polled` is omitted here, not passed as `false`: it is only assigned
247
247
  // `true` after `pollWhileSuspending` returns, so a throw mid-poll would
@@ -250,8 +250,8 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
250
250
  statusCode: 500,
251
251
  action: 'none',
252
252
  reason: REASON.getStateFailed,
253
- runnerId: doorbell.runnerId,
254
- microvmId: doorbell.microvmId,
253
+ runnerId: doorbellRequest.runnerId,
254
+ microvmId: doorbellRequest.microvmId,
255
255
  });
256
256
  }
257
257
  const state = described.state;
@@ -264,8 +264,8 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
264
264
  action: 'none',
265
265
  reason: REASON.suspendingPollExhausted,
266
266
  state,
267
- runnerId: doorbell.runnerId,
268
- microvmId: doorbell.microvmId,
267
+ runnerId: doorbellRequest.runnerId,
268
+ microvmId: doorbellRequest.microvmId,
269
269
  polled,
270
270
  });
271
271
  }
@@ -279,8 +279,8 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
279
279
  action: 'none',
280
280
  reason: state === 'RUNNING' ? REASON.alreadyRunning : REASON.alreadyStarting,
281
281
  state,
282
- runnerId: doorbell.runnerId,
283
- microvmId: doorbell.microvmId,
282
+ runnerId: doorbellRequest.runnerId,
283
+ microvmId: doorbellRequest.microvmId,
284
284
  polled,
285
285
  startedAt: described.startedAt,
286
286
  imageVersion: described.imageVersion,
@@ -290,15 +290,15 @@ async function handleWakeDoorbell(doorbell, shape, microvm, timing) {
290
290
  // request (#1906) can still set the same wire flag. Recreate loses VM-local
291
291
  // filesystem state; durable provider credentials survive in object storage,
292
292
  // but a manual paste/upload not yet synced there may be lost (#2071).
293
- if (doorbell.recreateOnOutdatedImage === true &&
294
- (await shouldRecreateForNewerImage(doorbell, shape, described.imageVersion, microvm))) {
295
- return runMicrovm(doorbell, shape, microvm, timing, polled, REASON.imageVersionOutdated, state);
293
+ if (doorbellRequest.recreateOnOutdatedImage === true &&
294
+ (await shouldRecreateForNewerImage(doorbellRequest, shape, described.imageVersion, microvm))) {
295
+ return runMicrovm(doorbellRequest, shape, microvm, timing, polled, REASON.imageVersionOutdated, state);
296
296
  }
297
- return resumeMicrovm(doorbell, doorbell.microvmId, shape, microvm, timing, polled, described.startedAt, described.imageVersion);
297
+ return resumeMicrovm(doorbellRequest, doorbellRequest.microvmId, shape, microvm, timing, polled, described.startedAt, described.imageVersion);
298
298
  default:
299
299
  // TERMINATED, TERMINATING, not_found — gone or going, so a fresh VM either
300
300
  // way. This is what self-heals a stale `microvm_id`.
301
- return runMicrovm(doorbell, shape, microvm, timing, polled, state === 'not_found' ? REASON.microvmNotFound : REASON.terminated, state);
301
+ return runMicrovm(doorbellRequest, shape, microvm, timing, polled, state === 'not_found' ? REASON.microvmNotFound : REASON.terminated, state);
302
302
  }
303
303
  }
304
304
  /**
@@ -333,13 +333,13 @@ function isClientTokenParameterMismatch(error) {
333
333
  const message = typeof e.message === 'string' ? e.message.toLowerCase() : '';
334
334
  return message.includes('clienttoken') && message.includes('different request parameters');
335
335
  }
336
- async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, state) {
336
+ async function runMicrovm(doorbellRequest, shape, microvm, timing, polled, reason, state) {
337
337
  let started;
338
338
  try {
339
339
  started = await (0, throttle_retry_1.withThrottleRetry)(() => microvm.run({
340
340
  imageIdentifier: shape.imageArn,
341
- runHookPayload: doorbell.runHookPayload,
342
- clientToken: clientTokenFor(doorbell),
341
+ runHookPayload: doorbellRequest.runHookPayload,
342
+ clientToken: clientTokenFor(doorbellRequest),
343
343
  }), timing);
344
344
  }
345
345
  catch (error) {
@@ -353,7 +353,7 @@ async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, stat
353
353
  // wakes.
354
354
  const name = error instanceof Error ? error.name : 'unknown';
355
355
  const message = error instanceof Error ? error.message : String(error);
356
- console.warn(`[doorbell] RunMicrovm clientToken already used for runner ${doorbell.runnerId}: ` +
356
+ console.warn(`[doorbell] RunMicrovm clientToken already used for runner ${doorbellRequest.runnerId}: ` +
357
357
  `${name}: ${message}`);
358
358
  // No `microvmId` (see the comment above), and therefore deliberately no
359
359
  // `startedAt` either: `decide`'s invariant is that `microvm_started_at`
@@ -365,18 +365,18 @@ async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, stat
365
365
  action: 'run',
366
366
  reason: REASON.runAlreadyStartedForToken,
367
367
  state,
368
- runnerId: doorbell.runnerId,
368
+ runnerId: doorbellRequest.runnerId,
369
369
  polled,
370
370
  });
371
371
  }
372
- console.error(`[doorbell] RunMicrovm failed for runner ${doorbell.runnerId}: ` +
372
+ console.error(`[doorbell] RunMicrovm failed for runner ${doorbellRequest.runnerId}: ` +
373
373
  `${error instanceof Error ? error.message : String(error)}`);
374
374
  return decide({
375
375
  statusCode: 500,
376
376
  action: 'run',
377
377
  reason: REASON.runFailed,
378
378
  state,
379
- runnerId: doorbell.runnerId,
379
+ runnerId: doorbellRequest.runnerId,
380
380
  polled,
381
381
  });
382
382
  }
@@ -385,14 +385,14 @@ async function runMicrovm(doorbell, shape, microvm, timing, polled, reason, stat
385
385
  action: 'run',
386
386
  reason,
387
387
  state,
388
- runnerId: doorbell.runnerId,
388
+ runnerId: doorbellRequest.runnerId,
389
389
  microvmId: started.microvmId,
390
390
  polled,
391
391
  startedAt: started.startedAt,
392
392
  imageVersion: started.imageVersion,
393
393
  });
394
394
  }
395
- async function resumeMicrovm(doorbell, microvmId, shape, microvm, timing, polled,
395
+ async function resumeMicrovm(doorbellRequest, microvmId, shape, microvm, timing, polled,
396
396
  // Both values come from the `describe()` result that led here because
397
397
  // `ResumeMicrovm` returns no lifecycle metadata of its own.
398
398
  startedAt, imageVersion) {
@@ -400,24 +400,24 @@ startedAt, imageVersion) {
400
400
  await (0, throttle_retry_1.withThrottleRetry)(() => microvm.resume(microvmId), timing);
401
401
  }
402
402
  catch (error) {
403
- console.error(`[doorbell] ResumeMicrovm failed for runner ${doorbell.runnerId}: ` +
403
+ console.error(`[doorbell] ResumeMicrovm failed for runner ${doorbellRequest.runnerId}: ` +
404
404
  `${error instanceof Error ? error.message : String(error)}`);
405
- return runMicrovm(doorbell, shape, microvm, timing, polled, REASON.resumeFailedFallingBackToRun, 'SUSPENDED');
405
+ return runMicrovm(doorbellRequest, shape, microvm, timing, polled, REASON.resumeFailedFallingBackToRun, 'SUSPENDED');
406
406
  }
407
407
  return decide({
408
408
  statusCode: 200,
409
409
  action: 'resume',
410
410
  reason: REASON.resumed,
411
411
  state: 'SUSPENDED',
412
- runnerId: doorbell.runnerId,
412
+ runnerId: doorbellRequest.runnerId,
413
413
  microvmId,
414
414
  polled,
415
415
  startedAt,
416
416
  imageVersion,
417
417
  });
418
418
  }
419
- async function suspendMicrovm(doorbell, microvm, timing) {
420
- const microvmId = doorbell.microvmId;
419
+ async function suspendMicrovm(doorbellRequest, microvm, timing) {
420
+ const microvmId = doorbellRequest.microvmId;
421
421
  if (microvmId === undefined) {
422
422
  // Nothing to suspend, and a redelivery would not change that — 200 so the
423
423
  // doorbell is not retried, but loudly enough to notice a mis-wired sender.
@@ -425,7 +425,7 @@ async function suspendMicrovm(doorbell, microvm, timing) {
425
425
  statusCode: 200,
426
426
  action: 'none',
427
427
  reason: REASON.suspendWithoutMicrovmId,
428
- runnerId: doorbell.runnerId,
428
+ runnerId: doorbellRequest.runnerId,
429
429
  });
430
430
  }
431
431
  let state;
@@ -434,13 +434,13 @@ async function suspendMicrovm(doorbell, microvm, timing) {
434
434
  ({ state } = await microvm.describe(microvmId));
435
435
  }
436
436
  catch (error) {
437
- console.error(`[doorbell] GetMicrovm failed for runner ${doorbell.runnerId}: ` +
437
+ console.error(`[doorbell] GetMicrovm failed for runner ${doorbellRequest.runnerId}: ` +
438
438
  `${error instanceof Error ? error.message : String(error)}`);
439
439
  return decide({
440
440
  statusCode: 500,
441
441
  action: 'none',
442
442
  reason: REASON.getStateFailed,
443
- runnerId: doorbell.runnerId,
443
+ runnerId: doorbellRequest.runnerId,
444
444
  microvmId,
445
445
  });
446
446
  }
@@ -453,7 +453,7 @@ async function suspendMicrovm(doorbell, microvm, timing) {
453
453
  action: 'none',
454
454
  reason: REASON.suspendAlreadyGone,
455
455
  state,
456
- runnerId: doorbell.runnerId,
456
+ runnerId: doorbellRequest.runnerId,
457
457
  microvmId,
458
458
  });
459
459
  }
@@ -461,14 +461,14 @@ async function suspendMicrovm(doorbell, microvm, timing) {
461
461
  await (0, throttle_retry_1.withThrottleRetry)(() => microvm.suspend(microvmId), timing);
462
462
  }
463
463
  catch (error) {
464
- console.error(`[doorbell] SuspendMicrovm failed for runner ${doorbell.runnerId}: ` +
464
+ console.error(`[doorbell] SuspendMicrovm failed for runner ${doorbellRequest.runnerId}: ` +
465
465
  `${error instanceof Error ? error.message : String(error)}`);
466
466
  return decide({
467
467
  statusCode: 500,
468
468
  action: 'suspend',
469
469
  reason: REASON.suspendFailed,
470
470
  state,
471
- runnerId: doorbell.runnerId,
471
+ runnerId: doorbellRequest.runnerId,
472
472
  microvmId,
473
473
  });
474
474
  }
@@ -477,7 +477,7 @@ async function suspendMicrovm(doorbell, microvm, timing) {
477
477
  action: 'suspend',
478
478
  reason: REASON.suspended,
479
479
  state,
480
- runnerId: doorbell.runnerId,
480
+ runnerId: doorbellRequest.runnerId,
481
481
  microvmId,
482
482
  });
483
483
  }
@@ -39,8 +39,7 @@ const cdk = __importStar(require("aws-cdk-lib"));
39
39
  const constructs_1 = require("constructs");
40
40
  const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
41
41
  const cr = __importStar(require("aws-cdk-lib/custom-resources"));
42
- /** The JSON field name inside the doorbell secret, same key the controller reads. */
43
- const DOORBELL_SECRET_KEY = 'DOORBELL_SECRET';
42
+ const constants_1 = require("../constants");
44
43
  /**
45
44
  * Deploy-time push: reports each shape's just-published MicroVM image version to
46
45
  * Evident, once per deploy that actually changes it. `imageVersions` is the
@@ -66,7 +65,7 @@ class ImageVersionReporter extends constructs_1.Construct {
66
65
  environment: {
67
66
  // ARN + field name only, never the value (mirrors the controller and waker).
68
67
  DOORBELL_SECRET_ARN: props.doorbellSecret.secretArn,
69
- DOORBELL_SECRET_KEY: DOORBELL_SECRET_KEY,
68
+ DOORBELL_SECRET_KEY: constants_1.DOORBELL_SECRET_KEY,
70
69
  EVIDENT_API_URL: props.evidentApiUrl,
71
70
  EVIDENT_RUNNER_ID: props.evidentRunnerId,
72
71
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evident-ai/runner-cdk",
3
- "version": "3.5.2-dev.43244a2",
3
+ "version": "3.5.2-dev.8d3aa06",
4
4
  "description": "Reusable CDK constructs for an Evident agent runner: a single scale-to-zero Fargate runner (task + service + per-agent self-stop role + waker Lambda), or a per-session AWS Lambda MicroVM that boots on demand and suspends between messages. Instantiate once per agent from your own stack.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",