@themoltnet/agent-daemon 0.57.0 → 0.57.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.
Files changed (2) hide show
  1. package/dist/cli.js +245 -306
  2. package/package.json +9 -9
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as cryptoService, defaultPiDaemonAdapter, i as compileExecutionPlan, n as createExecutionPlanSnapshot, r as parseCredentialRequirements, t as runtimeExecutionOffer } from "./pi.js";
3
2
  import { assertRuntimeAdapterSupportsProfile } from "./runtime.js";
3
+ import { a as cryptoService, defaultPiDaemonAdapter, i as compileExecutionPlan, n as createExecutionPlanSnapshot, r as parseCredentialRequirements, t as runtimeExecutionOffer } from "./pi.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { pino, transport } from "pino";
6
6
  import { Type } from "typebox";
@@ -10,7 +10,7 @@ import "multiformats/hashes/sha2";
10
10
  import "typebox/value";
11
11
  import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
12
12
  import { parseArgs, promisify } from "node:util";
13
- import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource, createLocalSeedSigner, resolveAgentIdentity, resolveProfileWarmSessionTtlSec, resolveRuntimeProfile, resolveRuntimeProfiles, validateRuntimeProfilePrerequisites } from "@themoltnet/agent-runtime";
13
+ import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource, createLocalSeedSigner, resolveAgentIdentity, resolveRuntimeProfile, resolveRuntimeProfiles, validateRuntimeProfilePrerequisites } from "@themoltnet/agent-runtime";
14
14
  import { GuestEnvironmentBoundaryError, assertGuestEnvironmentBoundary, createPiRetryTriage, findMainWorktree, isResolvedPathInsideRoot, normalizeRetryTriageResult, redactRetryTriageSecrets, resolveRuntimeProfileModel } from "@themoltnet/pi-runtime";
15
15
  import { FILE_SECRET_PROVIDER, FileSecretProvider, RegisterIdentityError, boundedIdentitySignal, connect, createNodeSecretProviderRegistry, register } from "@themoltnet/sdk/node";
16
16
  import { constants, copyFileSync, createReadStream, createWriteStream, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
@@ -1937,18 +1937,6 @@ var RuntimeProfileRef = Type.Object({ profileId: Type.String({ format: "uuid" })
1937
1937
  $id: "RuntimeProfileRef",
1938
1938
  additionalProperties: false
1939
1939
  });
1940
- var RuntimeProfileLeaseTtlSec = Type.Integer({
1941
- minimum: 1,
1942
- maximum: 86400
1943
- });
1944
- var RuntimeProfileHeartbeatIntervalMs = Type.Integer({
1945
- minimum: 0,
1946
- maximum: 36e5
1947
- });
1948
- var RuntimeProfileMaxBatchSize = Type.Integer({
1949
- minimum: 1,
1950
- maximum: 1e3
1951
- });
1952
1940
  var RuntimeProfileMaxTurns = Type.Integer({
1953
1941
  minimum: 0,
1954
1942
  maximum: 1e4
@@ -1977,21 +1965,8 @@ Type.Object({
1977
1965
  maxOutputTokens: RuntimeProfileNullableMaxOutputTokens,
1978
1966
  runtimeKind: RuntimeProfileRuntimeKind,
1979
1967
  sandbox: RuntimeProfileSandbox,
1980
- sessionStorageMode: Type.Literal("local"),
1981
- workspaceStorageMode: Type.Literal("local"),
1982
1968
  defaultWorkspaceMode: Type.Union([RuntimeProfileWorkspaceMode, Type.Null()]),
1983
1969
  allowedWorkspaceModes: RuntimeProfileAllowedWorkspaceModes,
1984
- sessionTtlSec: Type.Integer({
1985
- minimum: 1,
1986
- maximum: 86400
1987
- }),
1988
- workspaceTtlSec: Type.Integer({
1989
- minimum: 1,
1990
- maximum: 86400
1991
- }),
1992
- leaseTtlSec: RuntimeProfileLeaseTtlSec,
1993
- heartbeatIntervalMs: RuntimeProfileHeartbeatIntervalMs,
1994
- maxBatchSize: RuntimeProfileMaxBatchSize,
1995
1970
  maxTurns: RuntimeProfileMaxTurns,
1996
1971
  maxBashTimeouts: RuntimeProfileMaxBashTimeouts,
1997
1972
  toolEnforcement: RuntimeProfileToolEnforcement,
@@ -2124,6 +2099,7 @@ var ResolvedRuntimeSlot = Type.Object({
2124
2099
  workspace: Type.Union([RuntimeWorkspace, Type.Null()])
2125
2100
  }, { $id: "ResolvedRuntimeSlot" });
2126
2101
  Type.Object({ items: Type.Array(ResolvedRuntimeSlot) }, { $id: "RuntimeSlotListResponse" });
2102
+ var MAX_RUNTIME_WARM_RETENTION_SEC = 86400;
2127
2103
  Type.Object({
2128
2104
  agentName: Type.String({
2129
2105
  minLength: 1,
@@ -2150,7 +2126,11 @@ Type.Object({
2150
2126
  worktreeBranch: Type.Optional(Type.String({ minLength: 1 })),
2151
2127
  workspaceKind: Type.Optional(RuntimeWorkspaceKind),
2152
2128
  lastTaskId: Type.String({ format: "uuid" }),
2153
- lastAttemptN: Type.Integer({ minimum: 1 })
2129
+ lastAttemptN: Type.Integer({ minimum: 1 }),
2130
+ warmRetentionSec: Type.Integer({
2131
+ minimum: 0,
2132
+ maximum: MAX_RUNTIME_WARM_RETENTION_SEC
2133
+ })
2154
2134
  }, {
2155
2135
  $id: "BeginRuntimeSlotBody",
2156
2136
  additionalProperties: false
@@ -2172,7 +2152,11 @@ Type.Object({
2172
2152
  slotKey: Type.String({ minLength: 1 }),
2173
2153
  taskId: Type.String({ format: "uuid" }),
2174
2154
  attemptN: Type.Integer({ minimum: 1 }),
2175
- sessionPath: Type.Optional(Type.String({ minLength: 1 }))
2155
+ sessionPath: Type.Optional(Type.String({ minLength: 1 })),
2156
+ warmRetentionSec: Type.Integer({
2157
+ minimum: 0,
2158
+ maximum: MAX_RUNTIME_WARM_RETENTION_SEC
2159
+ })
2176
2160
  }, {
2177
2161
  $id: "FinishRuntimeSlotBody",
2178
2162
  additionalProperties: false
@@ -3461,7 +3445,7 @@ var COMMON_REQUIRED_FLAGS = `\
3461
3445
  --profile <uuid|name> Remote runtime profile. Repeat for poll/drain
3462
3446
  to declare priority order. Provider, model,
3463
3447
  sandbox policy, prerequisites, and runtime
3464
- defaults come from the selected profile.`;
3448
+ execution policy come from the selected profile.`;
3465
3449
  var COMMON_OPTIONAL_FLAGS = `\
3466
3450
  --sandbox <path> Deprecated. Remote runtime profiles define
3467
3451
  sandbox policy.
@@ -3473,24 +3457,10 @@ var COMMON_OPTIONAL_FLAGS = `\
3473
3457
  host git config. Configless agent-key runs must
3474
3458
  provide this flag or MOLTNET_GIT_AUTHOR.
3475
3459
  Env: MOLTNET_GIT_AUTHOR.
3476
- --lease-ttl-sec <n> Sliding liveness window. Silence longer than
3477
- this ends the attempt with lease_expired.
3478
- Default: 300.
3479
3460
  --heartbeat-interval-ms <n> Reporter heartbeat cadence. Default: 60000.
3480
- --max-batch-size <n> Reporter message batch size. Default: 50.
3481
- --flush-interval-ms <n> Reporter flush window. Default: 200.
3482
- --max-turns <n> Cap on tool-use turns per attempt; over this,
3483
- the pi session aborts and the attempt fails
3484
- with code 'max_turns_exceeded'. 0 = disabled.
3485
- Default: 0. Recommended ~30 for fulfill_brief.
3486
- --max-bash-timeouts <n> Cap on bash-tool timeouts per attempt; over
3487
- this, the pi session aborts and the attempt
3488
- fails with code 'max_bash_timeouts_exceeded'.
3489
- 0 = disabled. Default: 3.
3490
- --warm-session-ttl-sec <n> Resumability window for runtime slots
3461
+ --warm-retention-sec <n> Resumability window for runtime slots
3491
3462
  (Pi sessions + reusable worktrees) after use.
3492
- Default: 1800, or min(profile session/workspace
3493
- TTL) when --profile is set.
3463
+ Default: 1800.
3494
3464
  --debug Verbose logging: also log successful list/claim
3495
3465
  outcomes (candidate counts, claim attempts).`;
3496
3466
  var REGISTERED_TASK_TYPES = Object.keys(BUILT_IN_TASK_TYPES).sort();
@@ -3681,6 +3651,8 @@ Options:
3681
3651
  (or MOLTNET_AGENT_SERVER_ROOT).
3682
3652
  --api-url <url> Default MoltNet API for new managed agents.
3683
3653
  Default: https://api.themolt.net.
3654
+ --heartbeat-interval-ms <n> Child reporter heartbeat cadence. Default: 60000.
3655
+ --warm-retention-sec <n> Child session/workspace retention. Default: 1800.
3684
3656
 
3685
3657
  On macOS, the first interactive run asks to trust a per-user local CA in the
3686
3658
  login keychain and serves HTTPS. Run \`agent-daemon server trust --remove\` to
@@ -4189,10 +4161,10 @@ function slugifySessionComponent(input) {
4189
4161
  }
4190
4162
  //#endregion
4191
4163
  //#region src/lib/task-execution-plan.ts
4192
- function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlSec, runtimeProfileWorkspacePolicy = {}, attemptN) {
4164
+ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmRetentionSec, runtimeProfileWorkspacePolicy = {}, attemptN) {
4193
4165
  const descriptor = deriveTaskSessionDescriptor(task);
4194
4166
  const workspaceMode = resolveTaskWorkspaceMode(task, descriptor.policy, runtimeProfileWorkspacePolicy);
4195
- const slotKey = warmSessionTtlSec > 0 && descriptor.sessionKey ? buildRuntimeSlotKey(descriptor.sessionKey, identity.runtimeInstanceId) : null;
4167
+ const slotKey = warmRetentionSec > 0 && descriptor.sessionKey ? buildRuntimeSlotKey(descriptor.sessionKey, identity.runtimeInstanceId) : null;
4196
4168
  const workspaceScope = slotKey !== null ? descriptor.policy.workspaceScope : "attempt";
4197
4169
  const slotId = slotKey ? buildDaemonSlotId(identity, slotKey) : null;
4198
4170
  const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${boundedKeyDirComponent(slotId)}` : null;
@@ -4331,7 +4303,7 @@ function createExecutionPlanCache(args) {
4331
4303
  const key = buildClaimedTaskKey(claimedTask);
4332
4304
  const existing = cache.get(key);
4333
4305
  if (existing) return existing;
4334
- const plan = await maybeAttachWarmSlotContext(claimedTask, buildDaemonTaskExecutionPlan(claimedTask.task, args.stateDirs, args.slotIdentity, args.warmSessionTtlSec, args.workspacePolicy, claimedTask.attemptN), args.stateDirs, args.slotRegistry, runtimeSessionStore, sourceAttemptResolver);
4306
+ const plan = await maybeAttachWarmSlotContext(claimedTask, buildDaemonTaskExecutionPlan(claimedTask.task, args.stateDirs, args.slotIdentity, args.warmRetentionSec, args.workspacePolicy, claimedTask.attemptN), args.stateDirs, args.slotRegistry, runtimeSessionStore, sourceAttemptResolver);
4335
4307
  assertPlanAllowedByWorkspacePolicy(plan, args.workspacePolicy, args.slotIdentity.runtimeProfileId);
4336
4308
  cache.set(key, plan);
4337
4309
  return plan;
@@ -5022,7 +4994,8 @@ function ownBinding(bindings, name) {
5022
4994
  }
5023
4995
  //#endregion
5024
4996
  //#region ../../libs/execution-integrations/src/runtime-profile.ts
5025
- var CURRENT_EFFECTIVE_POLICY_SNAPSHOT_VERSION = "effective-policy:v1";
4997
+ var CURRENT_EFFECTIVE_POLICY_SNAPSHOT_VERSION = "effective-policy:v2";
4998
+ var DEFAULT_EXECUTION_LEASE_TTL_SEC = 300;
5026
4999
  /**
5027
5000
  * Maps resolved product authority into portable intent. Policy composition is
5028
5001
  * deliberately upstream: this boundary accepts no policy IDs and performs no
@@ -5046,7 +5019,7 @@ function executionIntentFromRuntimeProfile(input) {
5046
5019
  credentialRequirements: structuredClone(input.credentialRequirements),
5047
5020
  requiredCapabilities: [...input.requiredCapabilities ?? []],
5048
5021
  lease: {
5049
- ttlSec: input.profile.leaseTtlSec,
5022
+ ttlSec: DEFAULT_EXECUTION_LEASE_TTL_SEC,
5050
5023
  requiredControls: [...input.requiredLeaseControls ?? []]
5051
5024
  },
5052
5025
  network: {
@@ -5296,14 +5269,9 @@ async function logDaemonStartupFailure(input) {
5296
5269
  }
5297
5270
  //#endregion
5298
5271
  //#region src/lib/options.ts
5299
- var DEFAULTS = {
5300
- leaseTtlSec: 300,
5272
+ var DEFAULT_LOCAL_OPERATIONAL_SETTINGS = {
5301
5273
  heartbeatIntervalMs: 6e4,
5302
- maxBatchSize: 50,
5303
- flushIntervalMs: 200,
5304
- maxTurns: 0,
5305
- maxBashTimeouts: 3,
5306
- warmSessionTtlSec: 1800
5274
+ warmRetentionSec: 1800
5307
5275
  };
5308
5276
  var MissingRequiredOptionError = class extends Error {
5309
5277
  constructor(flag) {
@@ -5312,42 +5280,33 @@ var MissingRequiredOptionError = class extends Error {
5312
5280
  this.name = "MissingRequiredOptionError";
5313
5281
  }
5314
5282
  };
5315
- function parseCommonOptions(args, options = {}) {
5316
- const runtimeDefaults = {
5317
- leaseTtlSec: options.runtimeDefaults?.leaseTtlSec ?? DEFAULTS.leaseTtlSec,
5318
- heartbeatIntervalMs: options.runtimeDefaults?.heartbeatIntervalMs ?? DEFAULTS.heartbeatIntervalMs,
5319
- maxBatchSize: options.runtimeDefaults?.maxBatchSize ?? DEFAULTS.maxBatchSize,
5320
- maxTurns: options.runtimeDefaults?.maxTurns ?? DEFAULTS.maxTurns,
5321
- maxBashTimeouts: options.runtimeDefaults?.maxBashTimeouts ?? DEFAULTS.maxBashTimeouts,
5322
- warmSessionTtlSec: options.runtimeDefaults?.warmSessionTtlSec ?? DEFAULTS.warmSessionTtlSec
5323
- };
5283
+ function parseIdentityProcessOptions(args) {
5324
5284
  if (!args.agent) throw new MissingRequiredOptionError("agent");
5325
5285
  if (!/^[a-zA-Z0-9_-]+$/.test(args.agent)) throw new Error(`Invalid --agent "${args.agent}": must match /^[a-zA-Z0-9_-]+$/`);
5326
5286
  return {
5327
5287
  agent: args.agent,
5328
- leaseTtlSec: parsePositiveInt(args["lease-ttl-sec"], "lease-ttl-sec", runtimeDefaults.leaseTtlSec),
5329
- heartbeatIntervalMs: parseNonNegativeInt(args["heartbeat-interval-ms"], "heartbeat-interval-ms", runtimeDefaults.heartbeatIntervalMs),
5330
- maxBatchSize: parsePositiveInt(args["max-batch-size"], "max-batch-size", runtimeDefaults.maxBatchSize),
5331
- flushIntervalMs: parseNonNegativeInt(args["flush-interval-ms"], "flush-interval-ms", DEFAULTS.flushIntervalMs),
5332
- maxTurns: parseNonNegativeInt(args["max-turns"], "max-turns", runtimeDefaults.maxTurns),
5333
- maxBashTimeouts: parseNonNegativeInt(args["max-bash-timeouts"], "max-bash-timeouts", runtimeDefaults.maxBashTimeouts),
5334
- warmSessionTtlSec: parseNonNegativeInt(args["warm-session-ttl-sec"], "warm-session-ttl-sec", runtimeDefaults.warmSessionTtlSec),
5335
5288
  debug: args.debug === true
5336
5289
  };
5337
5290
  }
5338
- function parsePositiveInt(raw, name, defaultValue) {
5339
- if (raw === void 0) return defaultValue;
5340
- const v = Number(raw);
5341
- if (!Number.isInteger(v) || v < 1) throw new Error(`Invalid --${name} "${raw}": must be a positive integer`);
5342
- return v;
5291
+ function parseLocalOperationalSettings(args) {
5292
+ return {
5293
+ heartbeatIntervalMs: parseNonNegativeInt(args["heartbeat-interval-ms"], "heartbeat-interval-ms", DEFAULT_LOCAL_OPERATIONAL_SETTINGS.heartbeatIntervalMs),
5294
+ warmRetentionSec: parseNonNegativeInt(args["warm-retention-sec"], "warm-retention-sec", DEFAULT_LOCAL_OPERATIONAL_SETTINGS.warmRetentionSec, MAX_RUNTIME_WARM_RETENTION_SEC)
5295
+ };
5296
+ }
5297
+ function parseRuntimeCommandOptions(args) {
5298
+ return {
5299
+ identity: parseIdentityProcessOptions(args),
5300
+ operations: parseLocalOperationalSettings(args)
5301
+ };
5343
5302
  }
5344
- function parseNonNegativeInt(raw, name, defaultValue) {
5303
+ function parseNonNegativeInt(raw, name, defaultValue, maximum = Number.MAX_SAFE_INTEGER) {
5345
5304
  if (raw === void 0) return defaultValue;
5346
- const v = Number(raw);
5347
- if (!Number.isInteger(v) || v < 0) throw new Error(`Invalid --${name} "${raw}": must be a non-negative integer`);
5348
- return v;
5305
+ const value = Number(raw);
5306
+ if (!Number.isInteger(value) || value < 0 || value > maximum) throw new Error(`Invalid --${name} "${raw}": must be a non-negative integer no greater than ${maximum}`);
5307
+ return value;
5349
5308
  }
5350
- function commonOptionDefs() {
5309
+ function identityOptionDefs() {
5351
5310
  return {
5352
5311
  agent: {
5353
5312
  type: "string",
@@ -5355,18 +5314,18 @@ function commonOptionDefs() {
5355
5314
  },
5356
5315
  "agent-root": { type: "string" },
5357
5316
  "git-author": { type: "string" },
5358
- "lease-ttl-sec": { type: "string" },
5359
- "heartbeat-interval-ms": { type: "string" },
5360
- "max-batch-size": { type: "string" },
5361
- "flush-interval-ms": { type: "string" },
5362
- "max-turns": { type: "string" },
5363
- "max-bash-timeouts": { type: "string" },
5364
- "warm-session-ttl-sec": { type: "string" },
5365
5317
  debug: { type: "boolean" }
5366
5318
  };
5367
5319
  }
5320
+ function runtimeCommandOptionDefs() {
5321
+ return {
5322
+ ...identityOptionDefs(),
5323
+ "heartbeat-interval-ms": { type: "string" },
5324
+ "warm-retention-sec": { type: "string" }
5325
+ };
5326
+ }
5368
5327
  function validateTaskTypes(types) {
5369
- const unknown = types.filter((t) => !Object.prototype.hasOwnProperty.call(BUILT_IN_TASK_TYPES, t));
5328
+ const unknown = types.filter((taskType) => !Object.prototype.hasOwnProperty.call(BUILT_IN_TASK_TYPES, taskType));
5370
5329
  if (unknown.length > 0) throw new Error(`Unknown task type(s): ${unknown.join(", ")}. Known types: ${knownTaskTypesList()}.`);
5371
5330
  return [...types];
5372
5331
  }
@@ -5936,6 +5895,64 @@ function mergePiModels(store, repo) {
5936
5895
  return { providers };
5937
5896
  }
5938
5897
  //#endregion
5898
+ //#region src/lib/state-dir.ts
5899
+ function ensureDaemonStateDirs(mountPath) {
5900
+ const rootDir = join(mountPath, ".moltnet", "d");
5901
+ const piSessionsDir = join(rootDir, "pi-sessions");
5902
+ mkdirSync(piSessionsDir, { recursive: true });
5903
+ return {
5904
+ rootDir,
5905
+ piSessionsDir
5906
+ };
5907
+ }
5908
+ //#endregion
5909
+ //#region src/lib/prepare-runtime-profile.ts
5910
+ /** Validate and prepare a profile through the shared daemon execution path. */
5911
+ async function prepareRuntimeProfile(input) {
5912
+ const { profile } = input;
5913
+ assertRuntimeAdapterSupportsProfile(input.runtimeAdapter, profile);
5914
+ const preparedRuntime = attestPreparedRuntime(await input.runtimeAdapter.prepare({ profile }), input.signingPrivateKey);
5915
+ validateRuntimeProfilePrerequisites(profile, input.prerequisiteEnv, {
5916
+ tools: preparedRuntime.tools,
5917
+ executables: preparedRuntime.executables
5918
+ });
5919
+ assertGuestEnvironmentBoundary({
5920
+ forwardEnv: profile.requiredEnv,
5921
+ sandboxEnv: profile.sandboxConfig.env
5922
+ });
5923
+ await input.agent.tasks.registerExecutorManifest(await preparedRuntime.attestor.registration());
5924
+ const sandbox = {
5925
+ config: profile.sandboxConfig,
5926
+ rootDir: profile.mountPath,
5927
+ path: profile.source
5928
+ };
5929
+ const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
5930
+ const slotIdentity = {
5931
+ agentName: input.agentName,
5932
+ runtimeProfileId: profile.id,
5933
+ runtimeInstanceId: input.runtimeInstanceId
5934
+ };
5935
+ return {
5936
+ profile,
5937
+ preparedRuntime,
5938
+ sandbox,
5939
+ stateDirs,
5940
+ slotIdentity,
5941
+ executionPlans: createExecutionPlanCache({
5942
+ stateDirs,
5943
+ slotIdentity,
5944
+ warmRetentionSec: input.warmRetentionSec,
5945
+ workspacePolicy: {
5946
+ defaultWorkspaceMode: profile.defaultWorkspaceMode,
5947
+ allowedWorkspaceModes: profile.allowedWorkspaceModes
5948
+ },
5949
+ slotRegistry: input.slotRegistry,
5950
+ runtimeSessionStore: input.runtimeSessionStore,
5951
+ sourceAttemptResolver: input.sourceAttemptResolver
5952
+ })
5953
+ };
5954
+ }
5955
+ //#endregion
5939
5956
  //#region src/lib/runtime-context.ts
5940
5957
  var storage = new AsyncLocalStorage();
5941
5958
  function runWithDaemonRuntimeContext(context, callback) {
@@ -6331,13 +6348,14 @@ function createApiRuntimeSlotStore(args) {
6331
6348
  sessionPath: input.sessionPath ?? void 0,
6332
6349
  slotKey: input.slotKey,
6333
6350
  taskType: input.taskType,
6351
+ warmRetentionSec: input.warmRetentionSec,
6334
6352
  workspaceId: input.workspaceId ?? void 0,
6335
6353
  workspaceKind: input.workspaceKind,
6336
6354
  worktreeBranch: input.worktreeBranch ?? void 0,
6337
6355
  worktreePath: input.worktreePath ?? void 0
6338
6356
  }, { teamId: input.teamId });
6339
6357
  },
6340
- async finishSlot(teamId, taskId, attemptN, identity, slotKey, provider, model, sessionPath) {
6358
+ async finishSlot(teamId, taskId, attemptN, identity, slotKey, provider, model, sessionPath, warmRetentionSec) {
6341
6359
  await agent.runtimeSlots.finish({
6342
6360
  agentName: identity.agentName,
6343
6361
  attemptN,
@@ -6346,7 +6364,8 @@ function createApiRuntimeSlotStore(args) {
6346
6364
  provider,
6347
6365
  sessionPath: sessionPath ?? void 0,
6348
6366
  slotKey,
6349
- taskId
6367
+ taskId,
6368
+ warmRetentionSec
6350
6369
  }, { teamId });
6351
6370
  },
6352
6371
  async findLatestSlotByTaskAttempt(teamId, taskId, attemptN) {
@@ -6482,17 +6501,6 @@ function resolveOutputBranch(output) {
6482
6501
  return typeof branch === "string" && branch.length > 0 ? branch : null;
6483
6502
  }
6484
6503
  //#endregion
6485
- //#region src/lib/state-dir.ts
6486
- function ensureDaemonStateDirs(mountPath) {
6487
- const rootDir = join(mountPath, ".moltnet", "d");
6488
- const piSessionsDir = join(rootDir, "pi-sessions");
6489
- mkdirSync(piSessionsDir, { recursive: true });
6490
- return {
6491
- rootDir,
6492
- piSessionsDir
6493
- };
6494
- }
6495
- //#endregion
6496
6504
  //#region src/lib/turn-event-logger.ts
6497
6505
  function makeTurnEventHandler(base, context = {}) {
6498
6506
  const log = base.child({
@@ -6523,7 +6531,7 @@ async function runPolling(opts) {
6523
6531
  const { values } = parseArgs({
6524
6532
  args: opts.argv,
6525
6533
  options: {
6526
- ...commonOptionDefs(),
6534
+ ...runtimeCommandOptionDefs(),
6527
6535
  team: { type: "string" },
6528
6536
  "task-types": { type: "string" },
6529
6537
  "correlation-id": { type: "string" },
@@ -6561,9 +6569,9 @@ async function runPolling(opts) {
6561
6569
  return 1;
6562
6570
  }
6563
6571
  const diaryIds = parseCsv(values["diary-ids"]);
6564
- let baseCommon;
6572
+ let commandOptions;
6565
6573
  try {
6566
- baseCommon = parseCommonOptions(values);
6574
+ commandOptions = parseRuntimeCommandOptions(values);
6567
6575
  } catch (err) {
6568
6576
  if (err instanceof MissingRequiredOptionError) {
6569
6577
  console.error(`${err.message}\n`);
@@ -6572,6 +6580,7 @@ async function runPolling(opts) {
6572
6580
  }
6573
6581
  throw err;
6574
6582
  }
6583
+ const { identity, operations } = commandOptions;
6575
6584
  const pollIntervalMs = optionalPositiveInt(values["poll-interval-ms"], "poll-interval-ms", 2e3);
6576
6585
  const maxPollIntervalMs = optionalPositiveInt(values["max-poll-interval-ms"], "max-poll-interval-ms", 3e4);
6577
6586
  const listLimit = optionalPositiveInt(values["list-limit"], "list-limit", 10);
@@ -6596,7 +6605,7 @@ async function runPolling(opts) {
6596
6605
  const { ctx, signingPrivateKey, startupWhoami, agentIdentity, hostCapabilitySigner } = await (async () => {
6597
6606
  let gate = "resolve_agent_context";
6598
6607
  try {
6599
- const resolvedContext = await resolveAgentContext(baseCommon.agent, {
6608
+ const resolvedContext = await resolveAgentContext(identity.agent, {
6600
6609
  agentRootDir: explicitAgentRootDir,
6601
6610
  credentialSource: cfg.credentialSource,
6602
6611
  envApiUrl: cfg.apiUrl
@@ -6623,7 +6632,7 @@ async function runPolling(opts) {
6623
6632
  });
6624
6633
  gate = "resolve_agent_identity";
6625
6634
  const agentIdentity = await resolveDaemonAgentIdentity({
6626
- agentName: baseCommon.agent,
6635
+ agentName: identity.agent,
6627
6636
  whoami,
6628
6637
  credentialSource: cfg.credentialSource,
6629
6638
  agentDir: resolvedContext.agentDir,
@@ -6643,9 +6652,9 @@ async function runPolling(opts) {
6643
6652
  } catch (error) {
6644
6653
  await logDaemonStartupFailure({
6645
6654
  serviceName: `agent-daemon.${opts.modeLabel}`,
6646
- level: cfg.logLevel || (baseCommon.debug ? "debug" : "info"),
6655
+ level: cfg.logLevel || (identity.debug ? "debug" : "info"),
6647
6656
  gate,
6648
- agent: baseCommon.agent,
6657
+ agent: identity.agent,
6649
6658
  credentialSource: cfg.credentialSource,
6650
6659
  error
6651
6660
  });
@@ -6659,23 +6668,43 @@ async function runPolling(opts) {
6659
6668
  teamId,
6660
6669
  cwd: daemonRootDir
6661
6670
  });
6671
+ const { logger, shutdown: shutdownLogger } = createRootLogger({
6672
+ name: `agent-daemon.${opts.modeLabel}`,
6673
+ level: cfg.logLevel || (identity.debug ? "debug" : "info")
6674
+ });
6675
+ const rootLogger = logger.child({
6676
+ mode: opts.modeLabel,
6677
+ agent: identity.agent,
6678
+ teamId,
6679
+ runtimeProfileIds: resolvedProfiles.map((profile) => profile.id),
6680
+ runtimeProfileNames: resolvedProfiles.map((profile) => profile.name)
6681
+ });
6662
6682
  const runtimeAdapter = opts.runtimeAdapter ?? defaultPiDaemonAdapter;
6663
- const preparedRuntimes = /* @__PURE__ */ new Map();
6664
6683
  const profiles = [];
6684
+ const runtimes = /* @__PURE__ */ new Map();
6665
6685
  const skippedProfileBoundaries = [];
6686
+ const slotRegistry = createApiRuntimeSlotStore({ agent: ctx.agent });
6687
+ const runtimeSessionStore = createApiRuntimeSessionStore({
6688
+ agent: ctx.agent,
6689
+ logger: { warn: (context, message) => rootLogger.warn(context, message) }
6690
+ });
6691
+ const sourceAttemptResolver = createApiSourceAttemptResolver({ agent: ctx.agent });
6692
+ const runtimeInstanceId = createRuntimeInstanceId();
6666
6693
  for (const profile of resolvedProfiles) try {
6667
- assertRuntimeAdapterSupportsProfile(runtimeAdapter, profile);
6668
- const prepared = attestPreparedRuntime(await runtimeAdapter.prepare({ profile }), signingPrivateKey);
6669
- validateRuntimeProfilePrerequisites(profile, cfg.profilePrerequisiteEnv, {
6670
- tools: prepared.tools,
6671
- executables: prepared.executables
6672
- });
6673
- assertGuestEnvironmentBoundary({
6674
- forwardEnv: profile.requiredEnv,
6675
- sandboxEnv: profile.sandboxConfig.env
6694
+ const prepared = await prepareRuntimeProfile({
6695
+ agent: ctx.agent,
6696
+ agentName: identity.agent,
6697
+ profile,
6698
+ prerequisiteEnv: cfg.profilePrerequisiteEnv,
6699
+ runtimeAdapter,
6700
+ runtimeInstanceId,
6701
+ signingPrivateKey,
6702
+ slotRegistry,
6703
+ runtimeSessionStore,
6704
+ sourceAttemptResolver,
6705
+ warmRetentionSec: operations.warmRetentionSec
6676
6706
  });
6677
- await ctx.agent.tasks.registerExecutorManifest(await prepared.attestor.registration());
6678
- preparedRuntimes.set(profile.id, prepared);
6707
+ runtimes.set(profile.id, prepared);
6679
6708
  profiles.push(profile);
6680
6709
  } catch (error) {
6681
6710
  if (!(error instanceof GuestEnvironmentBoundaryError)) throw error;
@@ -6688,84 +6717,22 @@ async function runPolling(opts) {
6688
6717
  const details = skippedProfileBoundaries.map(({ profile, error }) => `${profile.name}: ${error.message}`).join("; ");
6689
6718
  throw new Error(`No safe runtime profiles remain. ${details}`);
6690
6719
  }
6691
- const slotRegistry = createApiRuntimeSlotStore({ agent: ctx.agent });
6692
- const runtimeSessionStore = createApiRuntimeSessionStore({
6693
- agent: ctx.agent,
6694
- logger: { warn: (context, message) => rootLogger.warn(context, message) }
6695
- });
6696
- const sourceAttemptResolver = createApiSourceAttemptResolver({ agent: ctx.agent });
6697
- const runtimeInstanceId = createRuntimeInstanceId();
6698
6720
  const piAgentDir = await resolvePiAgentDir(cfg, profiles[0].mountPath, profiles);
6699
6721
  process.once("exit", piAgentDir.cleanup);
6700
6722
  activatePiCodingAgentDir(piAgentDir.path, piAgentDir.env);
6701
- const runtimes = /* @__PURE__ */ new Map();
6702
- for (const profile of profiles) {
6703
- const common = parseCommonOptions(values, { runtimeDefaults: {
6704
- leaseTtlSec: profile.leaseTtlSec,
6705
- heartbeatIntervalMs: profile.heartbeatIntervalMs,
6706
- maxBatchSize: profile.maxBatchSize,
6707
- maxTurns: profile.maxTurns,
6708
- maxBashTimeouts: profile.maxBashTimeouts,
6709
- warmSessionTtlSec: resolveProfileWarmSessionTtlSec(profile)
6710
- } });
6711
- const sandbox = {
6712
- config: profile.sandboxConfig,
6713
- rootDir: profile.mountPath,
6714
- path: profile.source
6715
- };
6716
- const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
6717
- const slotIdentity = {
6718
- agentName: common.agent,
6719
- runtimeProfileId: profile.id,
6720
- runtimeInstanceId
6721
- };
6722
- const executionPlans = createExecutionPlanCache({
6723
- stateDirs,
6724
- slotIdentity,
6725
- warmSessionTtlSec: common.warmSessionTtlSec,
6726
- workspacePolicy: {
6727
- defaultWorkspaceMode: profile.defaultWorkspaceMode,
6728
- allowedWorkspaceModes: profile.allowedWorkspaceModes
6729
- },
6730
- slotRegistry,
6731
- runtimeSessionStore,
6732
- sourceAttemptResolver
6733
- });
6734
- runtimes.set(profile.id, {
6735
- common,
6736
- profile,
6737
- sandbox,
6738
- stateDirs,
6739
- slotIdentity,
6740
- executionPlans,
6741
- preparedRuntime: preparedRuntimes.get(profile.id)
6742
- });
6743
- }
6744
- const firstRuntime = runtimes.get(profiles[0].id);
6745
- if (!firstRuntime) throw new Error("No runtime profiles resolved");
6723
+ if (!runtimes.has(profiles[0].id)) throw new Error("No runtime profiles resolved");
6746
6724
  const otelShutdown = await initWorkerOtel({
6747
6725
  serviceName: opts.serviceName,
6748
6726
  agent: ctx.agent,
6749
6727
  endpoint: cfg.otelEndpoint,
6750
6728
  resourceAttributes: {
6751
6729
  "moltnet.team.id": teamId,
6752
- "moltnet.agent.name": baseCommon.agent,
6730
+ "moltnet.agent.name": identity.agent,
6753
6731
  "moltnet.credential.source": ctx.credentialSource,
6754
6732
  "moltnet.runtime_profile.count": String(profiles.length),
6755
6733
  "moltnet.runtime_profile.ids": profiles.map((p) => p.id).join(",")
6756
6734
  }
6757
6735
  });
6758
- const { logger, shutdown: shutdownLogger } = createRootLogger({
6759
- name: `agent-daemon.${opts.modeLabel}`,
6760
- level: cfg.logLevel || (baseCommon.debug ? "debug" : "info")
6761
- });
6762
- const rootLogger = logger.child({
6763
- mode: opts.modeLabel,
6764
- agent: baseCommon.agent,
6765
- teamId,
6766
- runtimeProfileIds: profiles.map((p) => p.id),
6767
- runtimeProfileNames: profiles.map((p) => p.name)
6768
- });
6769
6736
  for (const { profile, error } of skippedProfileBoundaries) rootLogger.warn({
6770
6737
  runtimeProfileId: profile.id,
6771
6738
  runtimeProfileName: profile.name,
@@ -6821,13 +6788,10 @@ async function runPolling(opts) {
6821
6788
  topK: profile.topK,
6822
6789
  maxOutputTokens: profile.maxOutputTokens,
6823
6790
  sandbox: runtime.sandbox.path,
6824
- leaseTtlSec: runtime.common.leaseTtlSec,
6825
- heartbeatIntervalMs: runtime.common.heartbeatIntervalMs,
6826
- maxTurns: runtime.common.maxTurns,
6827
- maxBashTimeouts: runtime.common.maxBashTimeouts,
6828
- warmSessionTtlSec: runtime.common.warmSessionTtlSec,
6829
- profileSessionTtlSec: profile.sessionTtlSec,
6830
- profileWorkspaceTtlSec: profile.workspaceTtlSec,
6791
+ heartbeatIntervalMs: operations.heartbeatIntervalMs,
6792
+ maxTurns: profile.maxTurns,
6793
+ maxBashTimeouts: profile.maxBashTimeouts,
6794
+ warmRetentionSec: operations.warmRetentionSec,
6831
6795
  defaultWorkspaceMode: profile.defaultWorkspaceMode,
6832
6796
  allowedWorkspaceModes: profile.allowedWorkspaceModes
6833
6797
  };
@@ -6852,7 +6816,7 @@ async function runPolling(opts) {
6852
6816
  runtimeSlotStore: slotRegistry,
6853
6817
  taskReader: ctx.agent.tasks
6854
6818
  }, {
6855
- agentName: selected.common.agent,
6819
+ agentName: identity.agent,
6856
6820
  mainWorktree: resolveMainWorktree$1(selected.sandbox.rootDir),
6857
6821
  runtimeInstanceId,
6858
6822
  runtimeProfileId: profile.id,
@@ -6885,12 +6849,8 @@ async function runPolling(opts) {
6885
6849
  teamId,
6886
6850
  taskTypes: taskTypes.length > 0 ? taskTypes : void 0,
6887
6851
  correlationId: values["correlation-id"],
6888
- profiles: profiles.map((profile) => ({
6889
- profileId: profile.id,
6890
- leaseTtlSec: requireRuntime(runtimes, profile.id).common.leaseTtlSec
6891
- })),
6852
+ profiles: profiles.map((profile) => ({ profileId: profile.id })),
6892
6853
  diaryIds: diaryIds.length > 0 ? diaryIds : void 0,
6893
- leaseTtlSec: firstRuntime.common.leaseTtlSec,
6894
6854
  listLimit,
6895
6855
  pollIntervalMs,
6896
6856
  maxPollIntervalMs,
@@ -6898,7 +6858,7 @@ async function runPolling(opts) {
6898
6858
  stopWhenEmpty: opts.stopWhenEmpty,
6899
6859
  waitForFirstTaskMs: waitForFirstTaskSec * 1e3,
6900
6860
  waitAfterTaskMs: waitAfterTaskSec * 1e3,
6901
- debug: baseCommon.debug,
6861
+ debug: identity.debug,
6902
6862
  traceIdlePolling: cfg.traceIdlePolling,
6903
6863
  logger: rootLogger,
6904
6864
  executorFingerprints: Object.fromEntries(profiles.map((profile) => [profile.id, requireRuntime(runtimes, profile.id).preparedRuntime.attestor.fingerprint])),
@@ -6907,14 +6867,11 @@ async function runPolling(opts) {
6907
6867
  sourceAttemptResolver
6908
6868
  }),
6909
6869
  makeReporter: (claimedTask) => {
6910
- const selected = runtimeForClaimedTask(runtimes, claimedTask);
6911
6870
  return new ApiTaskReporter({
6912
6871
  tasks: ctx.agent.tasks,
6913
6872
  teamId: claimedTask.task.teamId,
6914
- leaseTtlSec: selected.common.leaseTtlSec,
6915
- heartbeatIntervalMs: selected.common.heartbeatIntervalMs,
6916
- maxBatchSize: selected.common.maxBatchSize,
6917
- flushIntervalMs: selected.common.flushIntervalMs
6873
+ heartbeatIntervalMs: operations.heartbeatIntervalMs,
6874
+ logger: rootLogger
6918
6875
  });
6919
6876
  },
6920
6877
  onTaskFinished: async (output, claimedTask) => {
@@ -6962,7 +6919,7 @@ async function runPolling(opts) {
6962
6919
  },
6963
6920
  executeTask: async (claimedTask, reporter) => {
6964
6921
  const selected = runtimeForClaimedTask(runtimes, claimedTask);
6965
- const { common, executionPlans, profile, sandbox, slotIdentity, stateDirs } = selected;
6922
+ const { executionPlans, profile, sandbox, slotIdentity, stateDirs } = selected;
6966
6923
  if (runtimeCredentialConfig) await observeGovernancePlanSafely({
6967
6924
  config: runtimeCredentialConfig,
6968
6925
  profile,
@@ -7076,10 +7033,11 @@ async function runPolling(opts) {
7076
7033
  worktreeBranch: executionPlan.worktreeBranch,
7077
7034
  workspaceKind: executionPlan.workspaceKind,
7078
7035
  lastTaskId: claimedTask.task.id,
7079
- lastAttemptN: claimedTask.attemptN
7036
+ lastAttemptN: claimedTask.attemptN,
7037
+ warmRetentionSec: operations.warmRetentionSec
7080
7038
  });
7081
7039
  const rawExecuteTask = selected.preparedRuntime.createTaskExecutor({
7082
- agentName: common.agent,
7040
+ agentName: identity.agent,
7083
7041
  moltnetAgent: ctx.agent,
7084
7042
  agentIdentity,
7085
7043
  hostCapabilitySigner,
@@ -7109,8 +7067,8 @@ async function runPolling(opts) {
7109
7067
  makeExecutionPlan: (task) => executionPlans.getOrCreate(task),
7110
7068
  makeOnTurnEvent: makeTurnEventHandlerFactory(taskLogger),
7111
7069
  toolPolicyLogger: taskLogger,
7112
- maxTurns: common.maxTurns,
7113
- maxBashTimeouts: common.maxBashTimeouts
7070
+ maxTurns: profile.maxTurns,
7071
+ maxBashTimeouts: profile.maxBashTimeouts
7114
7072
  });
7115
7073
  try {
7116
7074
  active = {
@@ -7131,7 +7089,7 @@ async function runPolling(opts) {
7131
7089
  } finally {
7132
7090
  active = null;
7133
7091
  executionPlans.delete(claimedTask);
7134
- if (executionPlan.slotKey) await slotRegistry.finishSlot(claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN, slotIdentity, executionPlan.slotKey, profile.provider, profile.model, executionPlan.sessionPersistence ? resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir) : null);
7092
+ if (executionPlan.slotKey) await slotRegistry.finishSlot(claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN, slotIdentity, executionPlan.slotKey, profile.provider, profile.model, executionPlan.sessionPersistence ? resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir) : null, operations.warmRetentionSec);
7135
7093
  }
7136
7094
  }
7137
7095
  });
@@ -7207,7 +7165,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7207
7165
  const { values } = parseArgs({
7208
7166
  args: argv,
7209
7167
  options: {
7210
- ...commonOptionDefs(),
7168
+ ...runtimeCommandOptionDefs(),
7211
7169
  "task-id": {
7212
7170
  type: "string",
7213
7171
  short: "t"
@@ -7228,9 +7186,9 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7228
7186
  console.error(ONCE_HELP);
7229
7187
  return 1;
7230
7188
  }
7231
- let opts;
7189
+ let commandOptions;
7232
7190
  try {
7233
- opts = parseCommonOptions(values);
7191
+ commandOptions = parseRuntimeCommandOptions(values);
7234
7192
  } catch (err) {
7235
7193
  if (err instanceof MissingRequiredOptionError) {
7236
7194
  console.error(`${err.message}\n`);
@@ -7239,6 +7197,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7239
7197
  }
7240
7198
  throw err;
7241
7199
  }
7200
+ const { identity, operations } = commandOptions;
7242
7201
  if (values.sandbox) {
7243
7202
  console.error("Cannot use --sandbox. Remote runtime profiles define sandbox policy.");
7244
7203
  return 1;
@@ -7249,12 +7208,11 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7249
7208
  bindings: cfg.credentialBindings
7250
7209
  };
7251
7210
  const runtimeCredentialConfig = resolveCredentialEnforcement(cfg.credentialEnforcement, credentialSources) === "off" ? null : loadRuntimeCredentialConfig(credentialSources);
7252
- const initialOpts = opts;
7253
7211
  const explicitAgentRootDir = values["agent-root"] ? resolve(process.cwd(), values["agent-root"]) : void 0;
7254
7212
  const { ctx, signingPrivateKey, agentIdentity, hostCapabilitySigner } = await (async () => {
7255
7213
  let gate = "resolve_agent_context";
7256
7214
  try {
7257
- const resolvedContext = await resolveAgentContext(initialOpts.agent, {
7215
+ const resolvedContext = await resolveAgentContext(identity.agent, {
7258
7216
  agentRootDir: explicitAgentRootDir,
7259
7217
  credentialSource: cfg.credentialSource,
7260
7218
  envApiUrl: cfg.apiUrl
@@ -7281,7 +7239,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7281
7239
  });
7282
7240
  gate = "resolve_agent_identity";
7283
7241
  const agentIdentity = await resolveDaemonAgentIdentity({
7284
- agentName: initialOpts.agent,
7242
+ agentName: identity.agent,
7285
7243
  whoami,
7286
7244
  credentialSource: cfg.credentialSource,
7287
7245
  agentDir: resolvedContext.agentDir,
@@ -7300,9 +7258,9 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7300
7258
  } catch (error) {
7301
7259
  await logDaemonStartupFailure({
7302
7260
  serviceName: "agent-daemon.once",
7303
- level: cfg.logLevel || (initialOpts.debug ? "debug" : "info"),
7261
+ level: cfg.logLevel || (identity.debug ? "debug" : "info"),
7304
7262
  gate,
7305
- agent: initialOpts.agent,
7263
+ agent: identity.agent,
7306
7264
  credentialSource: cfg.credentialSource,
7307
7265
  error
7308
7266
  });
@@ -7316,34 +7274,23 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7316
7274
  teamId: values.team,
7317
7275
  cwd: daemonRootDir
7318
7276
  });
7319
- assertRuntimeAdapterSupportsProfile(runtimeAdapter, profile);
7320
- const preparedRuntime = attestPreparedRuntime(await runtimeAdapter.prepare({ profile }), signingPrivateKey);
7321
- validateRuntimeProfilePrerequisites(profile, cfg.profilePrerequisiteEnv, {
7322
- tools: preparedRuntime.tools,
7323
- executables: preparedRuntime.executables
7277
+ const { logger, shutdown: shutdownLogger } = createRootLogger({
7278
+ name: "agent-daemon.once",
7279
+ level: cfg.logLevel || (identity.debug ? "debug" : "info")
7324
7280
  });
7325
- assertGuestEnvironmentBoundary({
7326
- forwardEnv: profile.requiredEnv,
7327
- sandboxEnv: profile.sandboxConfig.env
7281
+ const rootLogger = logger.child({
7282
+ mode: "once",
7283
+ agent: identity.agent,
7284
+ provider: profile.provider,
7285
+ model: profile.model,
7286
+ thinkingLevel: profile.thinkingLevel,
7287
+ temperature: profile.temperature,
7288
+ topP: profile.topP,
7289
+ topK: profile.topK,
7290
+ maxOutputTokens: profile.maxOutputTokens,
7291
+ runtimeProfileId: profile.id,
7292
+ runtimeProfileName: profile.name
7328
7293
  });
7329
- await ctx.agent.tasks.registerExecutorManifest(await preparedRuntime.attestor.registration());
7330
- opts = parseCommonOptions(values, { runtimeDefaults: {
7331
- leaseTtlSec: profile.leaseTtlSec,
7332
- heartbeatIntervalMs: profile.heartbeatIntervalMs,
7333
- maxBatchSize: profile.maxBatchSize,
7334
- maxTurns: profile.maxTurns,
7335
- maxBashTimeouts: profile.maxBashTimeouts,
7336
- warmSessionTtlSec: resolveProfileWarmSessionTtlSec(profile)
7337
- } });
7338
- const sandbox = {
7339
- config: profile.sandboxConfig,
7340
- rootDir: profile.mountPath,
7341
- path: profile.source
7342
- };
7343
- const piAgentDir = await resolvePiAgentDir(cfg, sandbox.rootDir, [profile]);
7344
- process.once("exit", piAgentDir.cleanup);
7345
- activatePiCodingAgentDir(piAgentDir.path, piAgentDir.env);
7346
- const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
7347
7294
  const slotRegistry = createApiRuntimeSlotStore({ agent: ctx.agent });
7348
7295
  const runtimeSessionStore = createApiRuntimeSessionStore({
7349
7296
  agent: ctx.agent,
@@ -7351,30 +7298,29 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7351
7298
  });
7352
7299
  const sourceAttemptResolver = createApiSourceAttemptResolver({ agent: ctx.agent });
7353
7300
  const runtimeInstanceId = createRuntimeInstanceId();
7354
- const slotIdentity = {
7355
- agentName: opts.agent,
7356
- runtimeProfileId: profile.id,
7357
- runtimeInstanceId
7358
- };
7359
- const executionPlans = createExecutionPlanCache({
7360
- stateDirs,
7361
- slotIdentity,
7362
- warmSessionTtlSec: opts.warmSessionTtlSec,
7363
- workspacePolicy: {
7364
- defaultWorkspaceMode: profile.defaultWorkspaceMode,
7365
- allowedWorkspaceModes: profile.allowedWorkspaceModes
7366
- },
7301
+ const { executionPlans, preparedRuntime, sandbox, slotIdentity, stateDirs } = await prepareRuntimeProfile({
7302
+ agent: ctx.agent,
7303
+ agentName: identity.agent,
7304
+ profile,
7305
+ prerequisiteEnv: cfg.profilePrerequisiteEnv,
7306
+ runtimeAdapter,
7307
+ runtimeInstanceId,
7308
+ signingPrivateKey,
7367
7309
  slotRegistry,
7368
7310
  runtimeSessionStore,
7369
- sourceAttemptResolver
7311
+ sourceAttemptResolver,
7312
+ warmRetentionSec: operations.warmRetentionSec
7370
7313
  });
7314
+ const piAgentDir = await resolvePiAgentDir(cfg, sandbox.rootDir, [profile]);
7315
+ process.once("exit", piAgentDir.cleanup);
7316
+ activatePiCodingAgentDir(piAgentDir.path, piAgentDir.env);
7371
7317
  const otelShutdown = await initWorkerOtel({
7372
7318
  serviceName: "moltnet.agent-daemon.once",
7373
7319
  agent: ctx.agent,
7374
7320
  endpoint: cfg.otelEndpoint,
7375
7321
  resourceAttributes: {
7376
7322
  "moltnet.task.id": taskId,
7377
- "moltnet.agent.name": opts.agent,
7323
+ "moltnet.agent.name": identity.agent,
7378
7324
  "moltnet.credential.source": ctx.credentialSource,
7379
7325
  "moltnet.llm.provider": profile.provider,
7380
7326
  "moltnet.llm.model": profile.model,
@@ -7386,34 +7332,14 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7386
7332
  "moltnet.runtime_profile.id": profile.id
7387
7333
  }
7388
7334
  });
7389
- const { logger, shutdown: shutdownLogger } = createRootLogger({
7390
- name: "agent-daemon.once",
7391
- level: cfg.logLevel || (opts.debug ? "debug" : "info")
7392
- });
7393
- const rootLogger = logger.child({
7394
- mode: "once",
7395
- agent: opts.agent,
7396
- provider: profile.provider,
7397
- model: profile.model,
7398
- thinkingLevel: profile.thinkingLevel,
7399
- temperature: profile.temperature,
7400
- topP: profile.topP,
7401
- topK: profile.topK,
7402
- maxOutputTokens: profile.maxOutputTokens,
7403
- runtimeProfileId: profile.id,
7404
- runtimeProfileName: profile.name
7405
- });
7406
7335
  rootLogger.info({
7407
7336
  sandbox: sandbox.path,
7408
7337
  taskId,
7409
- leaseTtlSec: opts.leaseTtlSec,
7410
- heartbeatIntervalMs: opts.heartbeatIntervalMs,
7411
- maxTurns: opts.maxTurns,
7412
- maxBashTimeouts: opts.maxBashTimeouts,
7413
- warmSessionTtlSec: opts.warmSessionTtlSec,
7338
+ heartbeatIntervalMs: operations.heartbeatIntervalMs,
7339
+ maxTurns: profile.maxTurns,
7340
+ maxBashTimeouts: profile.maxBashTimeouts,
7341
+ warmRetentionSec: operations.warmRetentionSec,
7414
7342
  profileId: profile.id,
7415
- profileSessionTtlSec: profile.sessionTtlSec,
7416
- profileWorkspaceTtlSec: profile.workspaceTtlSec,
7417
7343
  piAgentDir: piAgentDir.path,
7418
7344
  piAgentDirSource: piAgentDir.source
7419
7345
  }, "agent-daemon.starting");
@@ -7425,7 +7351,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7425
7351
  runtimeSlotStore: slotRegistry,
7426
7352
  taskReader: ctx.agent.tasks
7427
7353
  }, {
7428
- agentName: opts.agent,
7354
+ agentName: identity.agent,
7429
7355
  mainWorktree: resolveMainWorktree(sandbox.rootDir),
7430
7356
  runtimeInstanceId,
7431
7357
  runtimeProfileId: profile.id,
@@ -7471,7 +7397,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7471
7397
  });
7472
7398
  try {
7473
7399
  const rawExecuteTask = preparedRuntime.createTaskExecutor({
7474
- agentName: opts.agent,
7400
+ agentName: identity.agent,
7475
7401
  moltnetAgent: ctx.agent,
7476
7402
  agentIdentity,
7477
7403
  hostCapabilitySigner,
@@ -7501,8 +7427,8 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7501
7427
  makeExecutionPlan: (claimedTask) => executionPlans.getOrCreate(claimedTask),
7502
7428
  onTurnEvent: makeTurnEventHandler(rootLogger, { taskId }),
7503
7429
  toolPolicyLogger: rootLogger,
7504
- maxTurns: opts.maxTurns,
7505
- maxBashTimeouts: opts.maxBashTimeouts
7430
+ maxTurns: profile.maxTurns,
7431
+ maxBashTimeouts: profile.maxBashTimeouts
7506
7432
  });
7507
7433
  const executeTask = async (claimedTask, reporter) => {
7508
7434
  if (runtimeCredentialConfig) await observeGovernancePlanSafely({
@@ -7559,7 +7485,8 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7559
7485
  worktreeBranch: executionPlan.worktreeBranch,
7560
7486
  workspaceKind: executionPlan.workspaceKind,
7561
7487
  lastTaskId: claimedTask.task.id,
7562
- lastAttemptN: claimedTask.attemptN
7488
+ lastAttemptN: claimedTask.attemptN,
7489
+ warmRetentionSec: operations.warmRetentionSec
7563
7490
  });
7564
7491
  activeAttemptN = claimedTask.attemptN;
7565
7492
  try {
@@ -7577,7 +7504,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7577
7504
  } finally {
7578
7505
  activeAttemptN = null;
7579
7506
  executionPlans.delete(claimedTask);
7580
- if (executionPlan.slotKey) await slotRegistry.finishSlot(claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN, slotIdentity, executionPlan.slotKey, profile.provider, profile.model, executionPlan.sessionPersistence ? resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir) : null);
7507
+ if (executionPlan.slotKey) await slotRegistry.finishSlot(claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN, slotIdentity, executionPlan.slotKey, profile.provider, profile.model, executionPlan.sessionPersistence ? resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir) : null, operations.warmRetentionSec);
7581
7508
  }
7582
7509
  };
7583
7510
  const writeCorrelationAnchors = makePrBodyAnchorWriter({
@@ -7590,17 +7517,14 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
7590
7517
  agent: ctx.agent,
7591
7518
  taskId,
7592
7519
  teamId: profile.teamId,
7593
- leaseTtlSec: opts.leaseTtlSec,
7594
7520
  profileId: profile.id,
7595
7521
  executorFingerprint: preparedRuntime.attestor.fingerprint
7596
7522
  }),
7597
7523
  makeReporter: () => new ApiTaskReporter({
7598
7524
  tasks: ctx.agent.tasks,
7599
7525
  teamId: profile.teamId,
7600
- leaseTtlSec: opts.leaseTtlSec,
7601
- heartbeatIntervalMs: opts.heartbeatIntervalMs,
7602
- maxBatchSize: opts.maxBatchSize,
7603
- flushIntervalMs: opts.flushIntervalMs
7526
+ heartbeatIntervalMs: operations.heartbeatIntervalMs,
7527
+ logger: rootLogger
7604
7528
  }),
7605
7529
  onTaskFinished: async (output, claimedTask) => {
7606
7530
  const resolved = await slotRegistry.findLatestSlotByTaskAttempt(claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN);
@@ -9842,6 +9766,7 @@ var RunManager = class {
9842
9766
  extraArgs: ["--agent-root", agentRoot]
9843
9767
  };
9844
9768
  })();
9769
+ const runtimeSettings = this.options.runtimeSettings ?? DEFAULT_LOCAL_OPERATIONAL_SETTINGS;
9845
9770
  const args = [
9846
9771
  ...runtimeModule ? ["--runtime", runtimeModule] : [],
9847
9772
  spec.mode,
@@ -9852,6 +9777,10 @@ var RunManager = class {
9852
9777
  ...spec.profiles.flatMap((profile) => ["--profile", profile]),
9853
9778
  "--task-types",
9854
9779
  spec.taskTypes.join(","),
9780
+ "--heartbeat-interval-ms",
9781
+ String(runtimeSettings.heartbeatIntervalMs),
9782
+ "--warm-retention-sec",
9783
+ String(runtimeSettings.warmRetentionSec),
9855
9784
  ...target.extraArgs
9856
9785
  ];
9857
9786
  if (activation.source === "managed") {
@@ -10522,7 +10451,11 @@ var AgentServerStatusSchema = Type.Object({
10522
10451
  identities: Type.Array(schemaRef(AgentServerIdentitySchema)),
10523
10452
  selectedIdentity: Type.Optional(Type.String()),
10524
10453
  providers: Type.Record(Type.String(), schemaRef(AgentServerProviderSchema)),
10525
- runs: Type.Array(schemaRef(AgentServerRunSchema))
10454
+ runs: Type.Array(schemaRef(AgentServerRunSchema)),
10455
+ runtimeSettings: Type.Object({
10456
+ heartbeatIntervalMs: Type.Integer({ minimum: 0 }),
10457
+ warmRetentionSec: Type.Integer({ minimum: 0 })
10458
+ })
10526
10459
  }, { $id: "AgentServerStatus" });
10527
10460
  var PairingStartedSchema = Type.Object({
10528
10461
  pairingId: Type.String(),
@@ -10996,7 +10929,8 @@ function registerStatusRoute(app, options, requirePairedOrigin) {
10996
10929
  identities: identityViews(store),
10997
10930
  ...selected ? { selectedIdentity: selected } : {},
10998
10931
  providers: options.providers.list(),
10999
- runs: runViews(runs)
10932
+ runs: runViews(runs),
10933
+ runtimeSettings: options.runtimeSettings ?? DEFAULT_LOCAL_OPERATIONAL_SETTINGS
11000
10934
  };
11001
10935
  });
11002
10936
  }
@@ -11496,6 +11430,8 @@ async function runAgentServer(argv) {
11496
11430
  "allowed-origins": { type: "string" },
11497
11431
  root: { type: "string" },
11498
11432
  "api-url": { type: "string" },
11433
+ "heartbeat-interval-ms": { type: "string" },
11434
+ "warm-retention-sec": { type: "string" },
11499
11435
  remove: { type: "boolean" }
11500
11436
  }
11501
11437
  });
@@ -11507,6 +11443,7 @@ async function runAgentServer(argv) {
11507
11443
  const allowedOrigins = parseAllowedOrigins(values["allowed-origins"] ?? (envConfig.allowedOrigins || DEFAULT_ALLOWED_ORIGINS));
11508
11444
  const root = values.root ?? resolveAgentServerRoot({ root: envConfig.root });
11509
11445
  const defaultApiUrl = values["api-url"] ?? (envConfig.apiUrl || DEFAULT_API_URL);
11446
+ const runtimeSettings = parseLocalOperationalSettings(values);
11510
11447
  const store = new AgentServerStore(root).ensure();
11511
11448
  if (trustRequested) return runTrustCommand(commandArgs, root);
11512
11449
  const { logger, shutdown: shutdownLogger } = createRootLogger({
@@ -11540,7 +11477,8 @@ async function runAgentServer(argv) {
11540
11477
  externalSecretProviders,
11541
11478
  baseEnv: processEnvSnapshot(),
11542
11479
  logger,
11543
- runtimeRegistry: new RuntimeRegistry(store.root)
11480
+ runtimeRegistry: new RuntimeRegistry(store.root),
11481
+ runtimeSettings
11544
11482
  });
11545
11483
  const tls = isMacos() ? await ensureTrustedLocalTls(root) : void 0;
11546
11484
  const app = buildAgentServer({
@@ -11559,6 +11497,7 @@ async function runAgentServer(argv) {
11559
11497
  cert: tls.cert
11560
11498
  } } : {},
11561
11499
  defaultApiUrl,
11500
+ runtimeSettings,
11562
11501
  ...envConfig.activeIdentity ? { activeIdentity: envConfig.activeIdentity } : {},
11563
11502
  version: "dev",
11564
11503
  logger,
@@ -11782,7 +11721,7 @@ async function runSyncSessions(argv) {
11782
11721
  const { values } = parseArgs({
11783
11722
  args: argv,
11784
11723
  options: {
11785
- ...commonOptionDefs(),
11724
+ ...identityOptionDefs(),
11786
11725
  team: { type: "string" },
11787
11726
  "runtime-profile-id": { type: "string" },
11788
11727
  state: { type: "string" },
@@ -11795,9 +11734,9 @@ async function runSyncSessions(argv) {
11795
11734
  console.error(SYNC_SESSIONS_HELP);
11796
11735
  return 1;
11797
11736
  }
11798
- let opts;
11737
+ let identity;
11799
11738
  try {
11800
- opts = parseCommonOptions(values);
11739
+ identity = parseIdentityProcessOptions(values);
11801
11740
  } catch (err) {
11802
11741
  if (err instanceof MissingRequiredOptionError) {
11803
11742
  console.error(`${err.message}\n`);
@@ -11811,7 +11750,7 @@ async function runSyncSessions(argv) {
11811
11750
  const agentRootDir = resolve(process.cwd(), values["agent-root"] ?? process.cwd());
11812
11751
  const explicitAgentRootDir = values["agent-root"] ? resolve(process.cwd(), values["agent-root"]) : void 0;
11813
11752
  const cfg = loadConfig();
11814
- const ctx = await resolveAgentContext(opts.agent, {
11753
+ const ctx = await resolveAgentContext(identity.agent, {
11815
11754
  credentialSource: cfg.credentialSource,
11816
11755
  envApiUrl: cfg.apiUrl,
11817
11756
  agentRootDir: explicitAgentRootDir
@@ -11826,7 +11765,7 @@ async function runSyncSessions(argv) {
11826
11765
  runtimeSlotStore: createApiRuntimeSlotStore({ agent: ctx.agent }),
11827
11766
  taskReader: ctx.agent.tasks
11828
11767
  }, {
11829
- agentName: opts.agent,
11768
+ agentName: identity.agent,
11830
11769
  dryRun: values["dry-run"] === true,
11831
11770
  limit,
11832
11771
  runtimeProfileId: values["runtime-profile-id"],
@@ -12003,7 +11942,7 @@ async function writeCache(cache) {
12003
11942
  }
12004
11943
  //#endregion
12005
11944
  //#region src/version.ts
12006
- var DAEMON_VERSION = "0.57.0";
11945
+ var DAEMON_VERSION = "0.57.1";
12007
11946
  //#endregion
12008
11947
  //#region src/cli.ts
12009
11948
  async function runAgentDaemonCli(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.57.0",
3
+ "version": "0.57.1",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "Universal MoltNet agent daemon host with a built-in Pi/Gondolin runtime and support for trusted operator-owned runtime modules. CLI: moltnet-agent.",
@@ -85,10 +85,10 @@
85
85
  "proper-lockfile": "4.1.2",
86
86
  "reflect-metadata": "^0.2.2",
87
87
  "typebox": "^1.2.8",
88
- "@themoltnet/os-keyring": "0.3.0",
89
88
  "@themoltnet/agent-runtime": "1.0.3",
90
- "@themoltnet/pi-runtime": "0.15.3",
91
- "@themoltnet/sdk": "0.142.0"
89
+ "@themoltnet/sdk": "0.142.0",
90
+ "@themoltnet/pi-runtime": "0.16.0",
91
+ "@themoltnet/os-keyring": "0.3.0"
92
92
  },
93
93
  "devDependencies": {
94
94
  "@fastify/swagger": "^9.6.1",
@@ -98,16 +98,16 @@
98
98
  "vite": "^8.0.0",
99
99
  "vite-plugin-dts": "^4.5.4",
100
100
  "vitest": "^3.0.0",
101
+ "@moltnet/api-client": "0.1.0",
101
102
  "@moltnet/agent-eval": "0.1.0",
102
- "@moltnet/crypto-service": "0.1.0",
103
- "@moltnet/bootstrap": "0.1.0",
104
103
  "@moltnet/execution-integrations": "0.1.0",
104
+ "@moltnet/crypto-service": "0.1.0",
105
105
  "@moltnet/execution-plan": "0.1.0",
106
- "@moltnet/api-client": "0.1.0",
107
- "@moltnet/models": "0.1.0",
106
+ "@moltnet/loopback-companion": "0.1.0",
108
107
  "@moltnet/observability": "0.1.0",
108
+ "@moltnet/models": "0.1.0",
109
+ "@moltnet/bootstrap": "0.1.0",
109
110
  "@moltnet/runtime-profiles": "0.1.0",
110
- "@moltnet/loopback-companion": "0.1.0",
111
111
  "@moltnet/tasks": "0.1.0"
112
112
  },
113
113
  "nx": {