@themoltnet/agent-daemon 0.29.0 → 0.29.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -166,9 +166,13 @@ For `themoltnet`, prefer a profile sandbox equivalent to this minimal policy:
166
166
  ```
167
167
 
168
168
  That's only a starting point. `vfs.shadow: ["node_modules"]` is an isolation
169
- primitive, not a performance recipe. In pnpm-heavy monorepos like this one,
170
- keep install hot paths off `/workspace` via guest-local store paths and
171
- `resumeCommands` tmpfs mounts.
169
+ primitive, not the whole performance recipe. In pnpm-heavy monorepos like this
170
+ one, keep the package-manager store off `/workspace` via guest-local store
171
+ paths such as `/opt/pnpm-store`, and let the Pi VM shadow `node_modules` into
172
+ VM-local executable storage for both current and future worktrees. For daemon
173
+ flows that need fast first installs, prewarm the store explicitly with
174
+ `pnpm fetch` after the sandbox is available instead of putting that network
175
+ operation in every resume.
172
176
 
173
177
  If a resume step assumes `/workspace` is a repo checkout, gate it on
174
178
  `resumeCommands[].when.workspaceMode` rather than on task type. Use:
package/dist/main.js CHANGED
@@ -10050,6 +10050,7 @@ var NON_RETRYABLE_CODES = new Set([
10050
10050
  "invalid_model",
10051
10051
  "output_rejected_by_server",
10052
10052
  "output_validation_failed",
10053
+ "submit_output_missing",
10053
10054
  "producer_context_missing",
10054
10055
  "running_max_bash_timeouts_exceeded",
10055
10056
  "running_max_turns_exceeded",
@@ -10186,6 +10187,32 @@ function withRetryInfo(error, info) {
10186
10187
  //#endregion
10187
10188
  //#region src/lib/finalize.ts
10188
10189
  /**
10190
+ * Flatten a classified attempt failure into the structured fields logged
10191
+ * alongside `attempt-failure-classified`. Surfaces the triage verdict that
10192
+ * was previously buried in `error.retry` so operators can see WHAT was
10193
+ * decided and WHY without decoding the attempt row, and binds the task
10194
+ * identifiers so a verdict can be pivoted back to the abandoned task/attempt
10195
+ * (the daemon log child carries agent/team/profile but not these). See #1528.
10196
+ *
10197
+ * `reason` is model-authored on the LLM-triage path, so it is run through
10198
+ * `redactRetryTriageSecrets` before it reaches the (wide-access) log sink —
10199
+ * parity with the `triage_failed` path, which already sanitizes.
10200
+ */
10201
+ function classificationLogFields(classified, ids) {
10202
+ const retry = classified.error.retry;
10203
+ return {
10204
+ taskId: ids.taskId,
10205
+ attemptN: ids.attemptN,
10206
+ ...ids.correlationId ? { correlationId: ids.correlationId } : {},
10207
+ source: classified.source,
10208
+ code: classified.error.code,
10209
+ retryable: classified.error.retryable,
10210
+ ...retry?.decision ? { decision: retry.decision } : {},
10211
+ ...retry?.confidence ? { confidence: retry.confidence } : {},
10212
+ ...retry?.reason ? { reason: redactRetryTriageSecrets(retry.reason) } : {}
10213
+ };
10214
+ }
10215
+ /**
10189
10216
  * Build the `daemonState` payload for a `/complete` call. Freeform
10190
10217
  * attempts report the local warm-slot hint when one exists; slot-less
10191
10218
  * freeform completions report `null` for `slotResumableUntil`. The server
@@ -10220,8 +10247,12 @@ async function finalizeTask(agent, output, ctx = {}) {
10220
10247
  });
10221
10248
  } catch (err) {
10222
10249
  const classified = await prepareAttemptFailure(agent, output, errorToFailReason(err), ctx);
10223
- ctx.log?.("complete-rejected-falling-back-to-fail", err);
10224
- ctx.log?.(`attempt-failure-classified:${classified.source}`);
10250
+ ctx.log?.("complete-rejected-falling-back-to-fail", { err });
10251
+ ctx.log?.("attempt-failure-classified", classificationLogFields(classified, {
10252
+ taskId: output.taskId,
10253
+ attemptN: output.attemptN,
10254
+ correlationId: ctx.task?.correlationId
10255
+ }));
10225
10256
  await agent.tasks.failAttempt(output.taskId, output.attemptN, { error: classified.error });
10226
10257
  return;
10227
10258
  }
@@ -10235,7 +10266,11 @@ async function finalizeTask(agent, output, ctx = {}) {
10235
10266
  };
10236
10267
  if ((await agent.tasks.heartbeat(output.taskId, output.attemptN, {})).cancelled) return;
10237
10268
  const classified = await prepareAttemptFailure(agent, output, error, ctx);
10238
- ctx.log?.(`attempt-failure-classified:${classified.source}`);
10269
+ ctx.log?.("attempt-failure-classified", classificationLogFields(classified, {
10270
+ taskId: output.taskId,
10271
+ attemptN: output.attemptN,
10272
+ correlationId: ctx.task?.correlationId
10273
+ }));
10239
10274
  await agent.tasks.failAttempt(output.taskId, output.attemptN, { error: classified.error });
10240
10275
  }
10241
10276
  function errorToFailReason(err) {
@@ -10266,7 +10301,7 @@ async function prepareAttemptFailure(agent, output, error, ctx) {
10266
10301
  maxAttempts: null
10267
10302
  };
10268
10303
  const recentMessages = classifyDeterministically(error) === "ambiguous" && ctx.retryTriage && ctx.task ? await agent.tasks.listMessages(output.taskId, output.attemptN).then((messages) => messages.slice(-12)).catch((err) => {
10269
- ctx.log?.("attempt-failure-message-fetch-failed", err);
10304
+ ctx.log?.("attempt-failure-message-fetch-failed", { err });
10270
10305
  return [];
10271
10306
  }) : [];
10272
10307
  return classifyAttemptFailure({
@@ -10292,7 +10327,7 @@ async function maybeWriteAnchors(output, ctx) {
10292
10327
  pullRequestUrl: pr
10293
10328
  });
10294
10329
  } catch (err) {
10295
- log?.("correlation-anchor-write-failed", err);
10330
+ log?.("correlation-anchor-write-failed", { err });
10296
10331
  }
10297
10332
  }
10298
10333
  //#endregion
@@ -11108,7 +11143,7 @@ async function runPolling(opts) {
11108
11143
  runtimeProfileName: selected.profile.name
11109
11144
  })
11110
11145
  }),
11111
- log: (msg, err) => rootLogger.warn({ err }, msg)
11146
+ log: (msg, fields) => rootLogger.warn(fields ?? {}, msg)
11112
11147
  });
11113
11148
  },
11114
11149
  executeTask: async (claimedTask, reporter) => {
@@ -11606,7 +11641,7 @@ async function runOnce(argv) {
11606
11641
  cwd: ctx.agentRootDir
11607
11642
  }),
11608
11643
  writeCorrelationAnchors,
11609
- log: (msg, err) => rootLogger.warn({ err }, msg)
11644
+ log: (msg, fields) => rootLogger.warn(fields ?? {}, msg)
11610
11645
  });
11611
11646
  },
11612
11647
  executeTask
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.29.0",
3
+ "version": "0.29.2",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "MoltNet agent daemon — claims and executes tasks (fulfill_brief, assess_brief) from the MoltNet task-service via Pi-headless. CLI: moltnet-agent.",
@@ -45,8 +45,8 @@
45
45
  "@opentelemetry/semantic-conventions": "^1.39.0",
46
46
  "pino": "^10.3.1",
47
47
  "pino-pretty": "^13.1.3",
48
- "@themoltnet/agent-runtime": "0.33.1",
49
- "@themoltnet/pi-extension": "0.31.0",
48
+ "@themoltnet/agent-runtime": "0.33.2",
49
+ "@themoltnet/pi-extension": "0.31.2",
50
50
  "@themoltnet/sdk": "0.117.0"
51
51
  },
52
52
  "devDependencies": {
@@ -54,9 +54,9 @@
54
54
  "typescript": "~5.9.2",
55
55
  "vite": "^8.0.0",
56
56
  "vitest": "^3.0.0",
57
+ "@moltnet/bootstrap": "0.1.0",
57
58
  "@moltnet/crypto-service": "0.1.0",
58
59
  "@moltnet/tasks": "0.1.0",
59
- "@moltnet/bootstrap": "0.1.0",
60
60
  "@moltnet/observability": "0.1.0"
61
61
  },
62
62
  "nx": {