@themoltnet/agent-daemon 0.7.0 → 0.9.0

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 (3) hide show
  1. package/README.md +36 -1
  2. package/dist/main.js +422 -176
  3. package/package.json +6 -6
package/README.md CHANGED
@@ -57,7 +57,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
57
57
  # https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/env-api-keys.ts
58
58
  ```
59
59
 
60
- To use an alternate auth-file path: `PI_AUTH_PATH=/abs/path/to/auth.json`.
60
+ To use a non-default auth directory: `PI_CODING_AGENT_DIR=/abs/path/to/.pi/agent`.
61
61
 
62
62
  ### Observability
63
63
 
@@ -254,6 +254,41 @@ moltnet entry list --diary-id "$MOLTNET_DIARY_ID" --limit 10 \
254
254
  --credentials "$PWD/.moltnet/local-dev/moltnet.json"
255
255
  ```
256
256
 
257
+ ### 4b. Create a `pr_review` smoke task
258
+
259
+ Use this path when you want to exercise the generic `pr_review` task type
260
+ against the local e2e stack before the new schema exists on a deployed API.
261
+
262
+ Start the daemon with `--task-types pr_review`:
263
+
264
+ ```bash
265
+ pnpm --filter @themoltnet/agent-daemon dev poll \
266
+ --agent local-dev \
267
+ --team "$MOLTNET_TEAM_ID" \
268
+ --task-types pr_review \
269
+ --provider openai-codex \
270
+ --model gpt-5.4-codex \
271
+ --debug
272
+ ```
273
+
274
+ Then, in another terminal, create the task:
275
+
276
+ ```bash
277
+ pnpm exec tsx tools/src/tasks/create-pr-review.ts \
278
+ --agent local-dev \
279
+ --pr <number> \
280
+ --repo <owner/repo>
281
+ ```
282
+
283
+ This helper stays imposer-only. It reads PR metadata, ensures the PR
284
+ correlation marker exists, loads the binary rubric, and creates the
285
+ `pr_review` task. The daemon-claimed LLM attempt remains responsible for
286
+ the review itself and for any requested outward action such as `gh pr comment`.
287
+
288
+ If you want an automated local check without real GitHub mutation, use the
289
+ stubbed `pr_review` lifecycle coverage in
290
+ `apps/agent-daemon/e2e/daemon.e2e.test.ts` instead of this manual smoke path.
291
+
257
292
  ### What to verify
258
293
 
259
294
  After the task completes, every entry produced **during the attempt** should:
package/dist/main.js CHANGED
@@ -3045,10 +3045,10 @@ function validateRubricWeights(rubric) {
3045
3045
  * complementary places.
3046
3046
  *
3047
3047
  * Before this envelope existed, criteria were scattered: a vestigial
3048
- * `criteriaCid` column nobody resolved, an `acceptanceCriteria: string[]`
3049
- * field on `fulfill_brief.input` that was "interpreted by the claiming
3050
- * agent," and inline `rubric` / `criteria[]` fields on judgment-task
3051
- * inputs. None of those were machine-verifiable end-to-end.
3048
+ * `criteriaCid` column nobody resolved, free-form prose on
3049
+ * `fulfill_brief.input`, and inline `rubric` / `criteria[]` fields on
3050
+ * judgment-task inputs. None of those were machine-verifiable
3051
+ * end-to-end.
3052
3052
  *
3053
3053
  * This module defines a single, content-addressable envelope an imposer
3054
3054
  * attaches to any task type. It has four orthogonal sections — pick
@@ -4185,7 +4185,6 @@ var FULFILL_BRIEF_TYPE = "fulfill_brief";
4185
4185
  var FulfillBriefInput = Type$2.Object({
4186
4186
  brief: Type$2.String({ minLength: 1 }),
4187
4187
  title: Type$2.Optional(Type$2.String()),
4188
- acceptanceCriteria: Type$2.Optional(Type$2.Array(Type$2.String())),
4189
4188
  successCriteria: Type$2.Optional(SuccessCriteria),
4190
4189
  seedFiles: Type$2.Optional(Type$2.Array(Type$2.String())),
4191
4190
  scopeHint: Type$2.Optional(Type$2.String())
@@ -4609,6 +4608,72 @@ async function onCreateJudgeEvalVariant(input, ctx) {
4609
4608
  }];
4610
4609
  }
4611
4610
  //#endregion
4611
+ //#region ../../libs/tasks/src/task-types/pr-review.ts
4612
+ var PR_REVIEW_TYPE = "pr_review";
4613
+ var PrReviewSubject = Type$2.Object({
4614
+ title: Type$2.String({ minLength: 1 }),
4615
+ summary: Type$2.String({ minLength: 1 }),
4616
+ resourceUrls: Type$2.Optional(Type$2.Array(Type$2.String({ minLength: 1 }))),
4617
+ inspectionHints: Type$2.Optional(Type$2.Array(Type$2.String({ minLength: 1 })))
4618
+ }, {
4619
+ $id: "PrReviewSubject",
4620
+ additionalProperties: false
4621
+ });
4622
+ var PrReviewInput = Type$2.Object({
4623
+ subject: PrReviewSubject,
4624
+ taskPrompt: Type$2.Optional(Type$2.String({ minLength: 1 })),
4625
+ successCriteria: SuccessCriteria
4626
+ }, {
4627
+ $id: "PrReviewInput",
4628
+ additionalProperties: false
4629
+ });
4630
+ var PrReviewScore = Type$2.Object({
4631
+ criterionId: Type$2.String({ minLength: 1 }),
4632
+ score: Type$2.Union([Type$2.Literal(0), Type$2.Literal(1)]),
4633
+ rationale: Type$2.String({ minLength: 1 })
4634
+ }, {
4635
+ $id: "PrReviewScore",
4636
+ additionalProperties: false
4637
+ });
4638
+ var PrReviewOutput = Type$2.Object({
4639
+ scores: Type$2.Array(PrReviewScore, { minItems: 1 }),
4640
+ composite: Type$2.Number({
4641
+ minimum: 0,
4642
+ maximum: 1
4643
+ }),
4644
+ verdict: Type$2.String({ minLength: 1 })
4645
+ }, {
4646
+ $id: "PrReviewOutput",
4647
+ additionalProperties: false
4648
+ });
4649
+ function requireBooleanRubric(rubric) {
4650
+ for (const criterion of rubric.criteria) if (criterion.scoring !== "boolean") return `pr_review requires boolean scoring for every rubric criterion; criterion "${criterion.id}" uses "${criterion.scoring}"`;
4651
+ return null;
4652
+ }
4653
+ function validatePrReviewInput(input) {
4654
+ const sc = input.successCriteria;
4655
+ if (!sc) return "successCriteria is required for judgment tasks";
4656
+ if (!sc.rubric) return "successCriteria.rubric is required for judgment tasks";
4657
+ return validateRubricWeights(sc.rubric) ?? requireBooleanRubric(sc.rubric);
4658
+ }
4659
+ function validatePrReviewOutput(output, input) {
4660
+ if (!input) return null;
4661
+ const scores = output.scores;
4662
+ const rubric = input.successCriteria.rubric;
4663
+ if (!rubric) return null;
4664
+ if (scores.length !== rubric.criteria.length) return `scores length ${scores.length} does not match rubric criteria length ${rubric.criteria.length}`;
4665
+ let composite = 0;
4666
+ for (let i = 0; i < rubric.criteria.length; i++) {
4667
+ const criterion = rubric.criteria[i];
4668
+ const score = scores[i];
4669
+ if (score.criterionId !== criterion.id) return `scores[${i}] has criterionId "${score.criterionId}" but rubric expects "${criterion.id}" in that position`;
4670
+ composite += criterion.weight * score.score;
4671
+ }
4672
+ const claimed = output.composite;
4673
+ if (Math.abs(claimed - composite) > 1e-6) return `composite ${claimed} does not match weighted sum ${composite.toFixed(6)}`;
4674
+ return null;
4675
+ }
4676
+ //#endregion
4612
4677
  //#region ../../libs/tasks/src/task-types/render-pack.ts
4613
4678
  /**
4614
4679
  * `render_pack` — turn a context pack into a signed rendered artefact.
@@ -4776,6 +4841,18 @@ var BUILT_IN_TASK_TYPES = {
4776
4841
  validateInput: validateJudgmentInput,
4777
4842
  validateInputAsync: validateAssessBriefInputAsync
4778
4843
  },
4844
+ [PR_REVIEW_TYPE]: {
4845
+ name: PR_REVIEW_TYPE,
4846
+ inputSchema: PrReviewInput,
4847
+ outputSchema: PrReviewOutput,
4848
+ outputKind: "judgment",
4849
+ workspaceMode: "dedicated_worktree",
4850
+ workspaceScope: "attempt",
4851
+ sessionScope: "none",
4852
+ requiresReferences: false,
4853
+ validateInput: validatePrReviewInput,
4854
+ validateOutput: validatePrReviewOutput
4855
+ },
4779
4856
  [CURATE_PACK_TYPE]: {
4780
4857
  name: CURATE_PACK_TYPE,
4781
4858
  inputSchema: CuratePackInput,
@@ -6169,78 +6246,6 @@ function isHelpFlag(args) {
6169
6246
  return args.includes("--help") || args.includes("-h");
6170
6247
  }
6171
6248
  //#endregion
6172
- //#region ../../libs/agent-runtime/src/subagent-output-contracts.ts
6173
- var REGISTRY = /* @__PURE__ */ new Map();
6174
- /**
6175
- * Register a subagent output contract. Idempotent: re-registering the
6176
- * same name with a different schema throws — contracts are meant to
6177
- * be stable. Re-registering with the identical contract object (same
6178
- * reference) is a no-op for HMR and test convenience.
6179
- *
6180
- * Typically called at module-init time alongside task-type
6181
- * registration. See task-types/index.ts in @moltnet/tasks for the
6182
- * conventional pattern.
6183
- */
6184
- function registerSubagentOutputContract(contract) {
6185
- if (!contract.name || contract.name.trim().length === 0) throw new Error("subagent output contract name is required");
6186
- if (!/^[a-z][a-z0-9_]*$/.test(contract.name)) throw new Error(`subagent output contract name '${contract.name}' must be lower_snake_case (starts with a letter, then [a-z0-9_]+)`);
6187
- const existing = REGISTRY.get(contract.name);
6188
- if (existing && existing !== contract) {
6189
- if (existing.parametersSchema !== contract.parametersSchema) throw new Error(`subagent output contract '${contract.name}' is already registered with a different schema; refusing to override`);
6190
- }
6191
- REGISTRY.set(contract.name, contract);
6192
- }
6193
- /**
6194
- * Resolve a subagent output contract by name. Returns `null` for
6195
- * unknown names — callers (the subagent custom tool) decide whether
6196
- * that's a tool error the parent LLM can recover from or a hard fail.
6197
- */
6198
- function getSubagentOutputContract(name) {
6199
- return REGISTRY.get(name) ?? null;
6200
- }
6201
- /**
6202
- * List all registered contracts. Useful for diagnostics and for the
6203
- * subagent tool's parameter description so a parent LLM can see what
6204
- * contracts are available without enumerating them in its prompt.
6205
- */
6206
- function listSubagentOutputContracts() {
6207
- return [...REGISTRY.values()];
6208
- }
6209
- //#endregion
6210
- //#region ../../libs/agent-runtime/src/built-in-contract-registrations.ts
6211
- /**
6212
- * Built-in subagent output contracts (#1087, #943).
6213
- *
6214
- * Why this is an exported function and not a module-init side
6215
- * effect:
6216
- *
6217
- * - The registry is process-global. Module-init registration
6218
- * fires exactly once per Node process (ESM modules are cached
6219
- * by URL). Tests that call `__resetSubagentOutputContractsForTests()`
6220
- * to start from an empty registry have no way to repopulate
6221
- * the built-ins without re-evaluating the module — which the
6222
- * cache prevents. PR #1101 review M4.
6223
- * - An explicit `registerBuiltInSubagentContracts()` lets the
6224
- * package index call it once at module load AND lets test
6225
- * setup hooks call it again after `__reset...`.
6226
- * - `registerSubagentOutputContract` is itself idempotent for
6227
- * identical re-registrations, so calling this function twice
6228
- * in the same process is safe.
6229
- *
6230
- * Adding a new built-in: extend the body of this function. Do not
6231
- * call `registerSubagentOutputContract` from anywhere else in the
6232
- * package — keeping all built-ins in one function makes the set
6233
- * auditable.
6234
- */
6235
- function registerBuiltInSubagentContracts() {
6236
- registerSubagentOutputContract({
6237
- name: "judge_eval_variant_result",
6238
- description: "Per-variant grading result produced by a subagent of judge_eval_variant: scores against the shared rubric, composite, and a 1-3 sentence verdict for a single variant.",
6239
- parametersSchema: JudgeEvalVariantResult
6240
- });
6241
- }
6242
- registerBuiltInSubagentContracts();
6243
- //#endregion
6244
6249
  //#region ../../libs/agent-runtime/src/context-bindings.ts
6245
6250
  var PROMPT_SEPARATOR = "\n\n---\n\n";
6246
6251
  /**
@@ -6388,6 +6393,20 @@ function buildFinalOutputBlock(opts) {
6388
6393
  return lines.join("\n");
6389
6394
  }
6390
6395
  //#endregion
6396
+ //#region ../../libs/agent-runtime/src/prompts/rubric-common.ts
6397
+ function renderRubricCriteriaList(rubric) {
6398
+ return rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
6399
+ }
6400
+ function renderRubricPreambleSection(rubric) {
6401
+ if (!rubric.preamble) return null;
6402
+ return [
6403
+ "### Rubric preamble",
6404
+ "",
6405
+ rubric.preamble,
6406
+ ""
6407
+ ].join("\n");
6408
+ }
6409
+ //#endregion
6391
6410
  //#region ../../libs/agent-runtime/src/prompts/assess-brief.ts
6392
6411
  /**
6393
6412
  * Build the first user-message prompt for an `assess_brief` judge attempt.
@@ -6413,13 +6432,8 @@ function buildFinalOutputBlock(opts) {
6413
6432
  */
6414
6433
  function buildAssessBriefUserPrompt(input, ctx) {
6415
6434
  const rubric = input.successCriteria.rubric;
6416
- const criteriaList = rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
6417
- const preambleSection = rubric.preamble ? [
6418
- "### Rubric preamble",
6419
- "",
6420
- rubric.preamble,
6421
- ""
6422
- ].join("\n") : "";
6435
+ const criteriaList = renderRubricCriteriaList(rubric);
6436
+ const preambleSection = renderRubricPreambleSection(rubric) ?? "";
6423
6437
  const workspaceSection = ctx.workspace?.mode === "dedicated_worktree" ? [
6424
6438
  "### Workspace",
6425
6439
  "",
@@ -6700,13 +6714,7 @@ function buildCuratePackUserPrompt(input, ctx) {
6700
6714
  * is told to inspect them itself.
6701
6715
  */
6702
6716
  function buildFulfillBriefUserPrompt(input, ctx) {
6703
- const { brief, title, acceptanceCriteria, seedFiles, scopeHint } = input;
6704
- const criteriaSection = acceptanceCriteria?.length ? [
6705
- "### Acceptance criteria",
6706
- "",
6707
- ...acceptanceCriteria.map((c) => `- ${c}`),
6708
- ""
6709
- ].join("\n") : "";
6717
+ const { brief, title, seedFiles, scopeHint } = input;
6710
6718
  const seedSection = seedFiles?.length ? [
6711
6719
  "### Seed files",
6712
6720
  "",
@@ -6754,7 +6762,6 @@ function buildFulfillBriefUserPrompt(input, ctx) {
6754
6762
  "",
6755
6763
  brief,
6756
6764
  "",
6757
- criteriaSection,
6758
6765
  seedSection,
6759
6766
  correlationSection,
6760
6767
  workspaceSection,
@@ -6894,13 +6901,8 @@ function buildJudgeEvalVariantUserPrompt(input, ctx) {
6894
6901
  function buildJudgePackUserPrompt(input, ctx) {
6895
6902
  const { renderedPackId, sourcePackId, successCriteria } = input;
6896
6903
  const rubric = successCriteria.rubric;
6897
- const criteriaList = rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
6898
- const preambleSection = rubric.preamble ? [
6899
- "### Rubric preamble",
6900
- "",
6901
- rubric.preamble,
6902
- ""
6903
- ].join("\n") : null;
6904
+ const criteriaList = renderRubricCriteriaList(rubric);
6905
+ const preambleSection = renderRubricPreambleSection(rubric);
6904
6906
  return [
6905
6907
  "# Judge Pack Agent",
6906
6908
  "",
@@ -7016,6 +7018,112 @@ function buildJudgePackUserPrompt(input, ctx) {
7016
7018
  ].filter((l) => l !== null).join("\n");
7017
7019
  }
7018
7020
  //#endregion
7021
+ //#region ../../libs/agent-runtime/src/prompts/pr-review.ts
7022
+ function buildPrReviewUserPrompt(input, ctx) {
7023
+ const rubric = input.successCriteria.rubric;
7024
+ const criteriaList = renderRubricCriteriaList(rubric);
7025
+ const preambleSection = renderRubricPreambleSection(rubric);
7026
+ const taskPromptSection = input.taskPrompt ? [
7027
+ "## Task-specific instructions",
7028
+ "",
7029
+ input.taskPrompt,
7030
+ ""
7031
+ ].join("\n") : "";
7032
+ const resourceSection = input.subject.resourceUrls && input.subject.resourceUrls.length > 0 ? [
7033
+ "### Resources",
7034
+ "",
7035
+ ...input.subject.resourceUrls.map((url) => `- ${url}`),
7036
+ ""
7037
+ ].join("\n") : "";
7038
+ const hintsSection = input.subject.inspectionHints && input.subject.inspectionHints.length > 0 ? [
7039
+ "### Inspection hints",
7040
+ "",
7041
+ ...input.subject.inspectionHints.map((hint) => `- ${hint}`),
7042
+ ""
7043
+ ].join("\n") : "";
7044
+ const workspaceSection = ctx.workspace?.mode === "dedicated_worktree" ? [
7045
+ "### Workspace",
7046
+ "",
7047
+ "This review attempt is running inside a dedicated disposable git",
7048
+ "worktree. Inspect and reason inside this workspace only.",
7049
+ ctx.workspace.branch ? `The current review branch is \`${ctx.workspace.branch}\`.` : "The current checkout is disposable and will be cleaned up when the task ends.",
7050
+ ""
7051
+ ].join("\n") : "";
7052
+ return [
7053
+ "# Review Agent",
7054
+ "",
7055
+ "You are an independent judge. You did NOT produce the subject under review.",
7056
+ "Assess it strictly against the rubric below and emit a structured judgment.",
7057
+ "You may inspect the local workspace and the referenced resources, but do NOT modify anything.",
7058
+ "",
7059
+ `Your diary ID is: ${ctx.diaryId}`,
7060
+ `This task's id is: ${ctx.taskId}`,
7061
+ "",
7062
+ "## Subject",
7063
+ "",
7064
+ `**Title:** ${input.subject.title}`,
7065
+ "",
7066
+ input.subject.summary,
7067
+ "",
7068
+ resourceSection,
7069
+ hintsSection,
7070
+ workspaceSection,
7071
+ "### Execution contract",
7072
+ "",
7073
+ "Treat the provided subject, resources, inspection hints, and any",
7074
+ "task-specific instructions as the full",
7075
+ "review contract for this task.",
7076
+ "",
7077
+ "If the task-specific instructions or inspection hints require an outward action tied to the review",
7078
+ "(for example publishing the judgment somewhere), perform that action as",
7079
+ "part of the task before reporting structured output.",
7080
+ "",
7081
+ "## Review workflow",
7082
+ "",
7083
+ "1. Read the subject summary, resources, inspection hints, and any",
7084
+ " task-specific instructions before scoring.",
7085
+ "2. Inspect the target artefact directly using the tools and resources the",
7086
+ " task makes available.",
7087
+ "3. If you are in a dedicated disposable worktree and need the review target",
7088
+ " checked out locally, do that work inside this disposable workspace only.",
7089
+ "4. Apply the rubric strictly. This task is about complexity and",
7090
+ " reviewability, not correctness or feature desirability.",
7091
+ "5. Perform any required outward action before emitting the final",
7092
+ " structured output.",
7093
+ "",
7094
+ taskPromptSection,
7095
+ preambleSection,
7096
+ "## Criteria",
7097
+ "",
7098
+ criteriaList,
7099
+ "",
7100
+ "### Scoring rules",
7101
+ "",
7102
+ "- Every criterion uses binary scoring only.",
7103
+ "- Score `1` when the subject clearly clears the criterion.",
7104
+ "- Score `0` when it does not, or when the evidence is ambiguous.",
7105
+ "- `rationale` is REQUIRED for every score. Keep it concrete and audit-friendly.",
7106
+ "- Compute `composite = Σ(weight_i × score_i)` exactly; the runtime rejects mismatches.",
7107
+ "",
7108
+ "Write a signed diary entry (tags: `judgment`, `pr_review`) capturing the rationale before reporting structured output.",
7109
+ "",
7110
+ buildFinalOutputBlock({
7111
+ taskType: "pr_review",
7112
+ outputSchemaName: "PrReviewOutput",
7113
+ shapeSketch: [
7114
+ "{",
7115
+ " \"scores\": [",
7116
+ " { \"criterionId\": \"...\", \"score\": 0, \"rationale\": \"...\" }",
7117
+ " ],",
7118
+ " \"composite\": <sum-of-weighted-binary-scores>,",
7119
+ " \"verdict\": \"<1-3 sentence overall>\"",
7120
+ "}"
7121
+ ].join("\n"),
7122
+ extraNotes: ["`scores` MUST stay in the same order as the rubric criteria.", "`score` MUST be exactly `0` or `1` for every criterion."]
7123
+ })
7124
+ ].filter(Boolean).join("\n");
7125
+ }
7126
+ //#endregion
7019
7127
  //#region ../../libs/agent-runtime/src/prompts/render-pack.ts
7020
7128
  /**
7021
7129
  * Build the first user-message prompt for a `render_pack` task. Almost mechanical:
@@ -7198,6 +7306,16 @@ function buildTaskUserPrompt(task, ctx) {
7198
7306
  diaryId: ctx.diaryId,
7199
7307
  taskId: ctx.taskId
7200
7308
  });
7309
+ case PR_REVIEW_TYPE:
7310
+ if (!Check(PrReviewInput, task.input)) {
7311
+ const errors = [...Errors(PrReviewInput, task.input)];
7312
+ throw new Error(`pr_review input failed validation: ${JSON.stringify(errors.slice(0, 3))}`);
7313
+ }
7314
+ return buildPrReviewUserPrompt(task.input, {
7315
+ diaryId: ctx.diaryId,
7316
+ taskId: ctx.taskId,
7317
+ workspace: ctx.workspace
7318
+ });
7201
7319
  case JUDGE_EVAL_VARIANT_TYPE:
7202
7320
  if (!Check(JudgeEvalVariantInput, task.input)) {
7203
7321
  const errors = [...Errors(JudgeEvalVariantInput, task.input)];
@@ -13916,6 +14034,31 @@ function abortableSleep(ms, signal) {
13916
14034
  });
13917
14035
  }
13918
14036
  //#endregion
14037
+ //#region ../../libs/agent-runtime/src/subagent-output-contracts.ts
14038
+ /**
14039
+ * Construct an immutable contract registry from a static list.
14040
+ *
14041
+ * The resulting registry is safe to share across sessions and
14042
+ * invocations — no mutation is possible after construction.
14043
+ */
14044
+ function createSubagentContractRegistry(contracts) {
14045
+ const lookup = /* @__PURE__ */ new Map();
14046
+ for (const c of contracts) {
14047
+ if (!c.name || c.name.trim().length === 0) throw new Error("subagent output contract name is required");
14048
+ if (!/^[a-z][a-z0-9_]*$/.test(c.name)) throw new Error(`subagent output contract name '${c.name}' must be lower_snake_case (starts with a letter, then [a-z0-9_]+)`);
14049
+ if (lookup.has(c.name)) throw new Error(`duplicate subagent output contract name '${c.name}' in constructor args`);
14050
+ lookup.set(c.name, c);
14051
+ }
14052
+ return {
14053
+ get(name) {
14054
+ return lookup.get(name) ?? null;
14055
+ },
14056
+ list() {
14057
+ return [...lookup.values()];
14058
+ }
14059
+ };
14060
+ }
14061
+ //#endregion
13919
14062
  //#region ../../libs/pi-extension/src/moltnet/render-phase6.ts
13920
14063
  function slugToTitle(value) {
13921
14064
  return value.split(/[:/_-]+/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" ");
@@ -14892,7 +15035,8 @@ function findMainWorktree() {
14892
15035
  function loadCredentials(agentDir) {
14893
15036
  const moltnetJson = readFileSync(path.join(agentDir, "moltnet.json"), "utf8");
14894
15037
  const agentEnvRaw = readFileSync(path.join(agentDir, "env"), "utf8");
14895
- const piAuthPath = process.env.PI_AUTH_PATH ?? path.join(process.env.HOME ?? "", ".pi", "agent", "auth.json");
15038
+ const piAgentDir = process.env.PI_CODING_AGENT_DIR ?? path.join(process.env.HOME ?? "", ".pi", "agent");
15039
+ const piAuthPath = path.join(piAgentDir, "auth.json");
14896
15040
  const piAuthJson = existsSync(piAuthPath) ? readFileSync(piAuthPath, "utf8") : null;
14897
15041
  const gitconfigPath = path.join(agentDir, "gitconfig");
14898
15042
  const gitconfig = existsSync(gitconfigPath) ? readFileSync(gitconfigPath, "utf8") : null;
@@ -15404,7 +15548,7 @@ async function buildAgentSession(args) {
15404
15548
  spanAttributes: args.otelSpanAttrs
15405
15549
  });
15406
15550
  const resourceLoader = new DefaultResourceLoader({
15407
- cwd: args.mountPath,
15551
+ cwd: args.cwdPath,
15408
15552
  agentDir: args.piAuthDir,
15409
15553
  extensionFactories: [piOtelExtension],
15410
15554
  appendSystemPrompt: args.appendSystemPrompt,
@@ -15412,12 +15556,12 @@ async function buildAgentSession(args) {
15412
15556
  });
15413
15557
  await resourceLoader.reload();
15414
15558
  const sessionManager = args.sessionPersistence ? await resolvePersistentSessionManager({
15415
- cwd: args.mountPath,
15559
+ cwd: args.cwdPath,
15416
15560
  sessionDir: args.sessionPersistence.sessionDir
15417
- }) : SessionManager.inMemory(args.mountPath);
15561
+ }) : SessionManager.inMemory(args.cwdPath);
15418
15562
  return (await createAgentSession({
15419
15563
  agentDir: args.piAuthDir,
15420
- cwd: args.mountPath,
15564
+ cwd: args.cwdPath,
15421
15565
  model: args.modelHandle,
15422
15566
  customTools: args.customTools,
15423
15567
  sessionManager,
@@ -15662,6 +15806,7 @@ var DEFAULT_SUBAGENT_TIMEOUT_MS = 300 * 1e3;
15662
15806
  */
15663
15807
  function createSubagentTool(args) {
15664
15808
  const buildSession = args.buildAgentSession ?? buildAgentSession;
15809
+ const { contractRegistry } = args;
15665
15810
  let callCount = 0;
15666
15811
  return {
15667
15812
  tool: defineTool({
@@ -15672,8 +15817,8 @@ function createSubagentTool(args) {
15672
15817
  async execute(_id, params) {
15673
15818
  if (!Check(SubagentToolParameters, params)) return toolError(`subagent: invalid parameters: ${JSON.stringify([...Errors(SubagentToolParameters, params)].slice(0, 3))}`);
15674
15819
  const { task, output_schema } = params;
15675
- const contract = getSubagentOutputContract(output_schema);
15676
- if (!contract) return toolError(`subagent: unknown output_schema "${output_schema}". Registered contracts: [${listSubagentOutputContracts().map((c) => c.name).join(", ")}]`);
15820
+ const contract = contractRegistry.get(output_schema);
15821
+ if (!contract) return toolError(`subagent: unknown output_schema "${output_schema}". Registered contracts: [${contractRegistry.list().map((c) => c.name).join(", ")}]`);
15677
15822
  callCount += 1;
15678
15823
  const callIndex = callCount;
15679
15824
  let captured = null;
@@ -15703,6 +15848,7 @@ function createSubagentTool(args) {
15703
15848
  });
15704
15849
  const session = await buildSession({
15705
15850
  mountPath: args.mountPath,
15851
+ cwdPath: args.cwdPath ?? args.mountPath,
15706
15852
  piAuthDir: args.piAuthDir,
15707
15853
  modelHandle: args.modelHandle,
15708
15854
  agentName: args.agentName,
@@ -16043,6 +16189,7 @@ function prepareTaskWorkspace(task, requestedMountPath, executionPlan) {
16043
16189
  const branch = executionPlan?.worktreeBranch ?? null;
16044
16190
  if (!branch) return {
16045
16191
  mountPath: requestedMountPath,
16192
+ cwdPath: requestedMountPath,
16046
16193
  mode: "shared_mount",
16047
16194
  branch: null,
16048
16195
  cleanup: () => {}
@@ -16050,7 +16197,7 @@ function prepareTaskWorkspace(task, requestedMountPath, executionPlan) {
16050
16197
  const mainRepo = findMainWorktree();
16051
16198
  const worktreeDir = resolveTaskWorktreePath(mainRepo, executionPlan?.workspaceId ?? `task-${task.id}`);
16052
16199
  const relMount = relative(mainRepo, requestedMountPath);
16053
- const mountPath = relMount === "" || relMount.startsWith("..") ? worktreeDir : join(worktreeDir, relMount);
16200
+ const cwdPath = relMount === "" || relMount.startsWith("..") ? worktreeDir : join(worktreeDir, relMount);
16054
16201
  const keepWorkspace = executionPlan?.workspaceScope === "session" && executionPlan.sessionKey !== null;
16055
16202
  if (keepWorkspace) ensureReusableTaskWorktree(mainRepo, worktreeDir, branch);
16056
16203
  else {
@@ -16058,7 +16205,8 @@ function prepareTaskWorkspace(task, requestedMountPath, executionPlan) {
16058
16205
  addTaskWorktree(mainRepo, worktreeDir, branch);
16059
16206
  }
16060
16207
  return {
16061
- mountPath,
16208
+ mountPath: mainRepo,
16209
+ cwdPath,
16062
16210
  mode: "dedicated_worktree",
16063
16211
  branch,
16064
16212
  cleanup: keepWorkspace ? () => {} : () => {
@@ -16171,15 +16319,24 @@ var noopTurnEventHandler = () => {};
16171
16319
  function createPiTaskExecutor(opts) {
16172
16320
  let cachedCheckpoint = opts.checkpointPath ?? null;
16173
16321
  return async (claimedTask, reporter) => {
16174
- if (!cachedCheckpoint) cachedCheckpoint = await ensureSnapshot({
16175
- config: opts.sandboxConfig?.snapshot,
16176
- onProgress: opts.onSnapshotProgress ?? ((m) => {
16177
- process.stderr.write(`[snapshot] ${m}\n`);
16178
- })
16322
+ const reporterWasOpened = !reporter.cancelSignal.aborted;
16323
+ if (reporterWasOpened) await reporter.open({
16324
+ taskId: claimedTask.task.id,
16325
+ attemptN: claimedTask.attemptN
16179
16326
  });
16180
16327
  return executePiTask(claimedTask, reporter, {
16181
16328
  ...opts,
16182
- checkpointPath: cachedCheckpoint
16329
+ checkpointPath: cachedCheckpoint ?? void 0,
16330
+ resolveCheckpointPath: async () => {
16331
+ if (!cachedCheckpoint) cachedCheckpoint = await ensureSnapshot({
16332
+ config: opts.sandboxConfig?.snapshot,
16333
+ onProgress: opts.onSnapshotProgress ?? ((m) => {
16334
+ process.stderr.write(`[snapshot] ${m}\n`);
16335
+ })
16336
+ });
16337
+ return cachedCheckpoint;
16338
+ },
16339
+ reporterAlreadyOpened: reporterWasOpened
16183
16340
  });
16184
16341
  };
16185
16342
  }
@@ -16195,8 +16352,9 @@ async function executePiTask(claimedTask, reporter, opts) {
16195
16352
  const startTime = Date.now();
16196
16353
  const requestedMountPath = opts.mountPath ?? process.cwd();
16197
16354
  const executionPlan = opts.makeExecutionPlan?.(claimedTask) ?? null;
16198
- const workspace = prepareTaskWorkspace(task, requestedMountPath, executionPlan);
16199
- const mountPath = workspace.mountPath;
16355
+ let workspace = null;
16356
+ let mountPath = requestedMountPath;
16357
+ let cwdPath = requestedMountPath;
16200
16358
  if (reporter.cancelSignal.aborted) return {
16201
16359
  taskId: task.id,
16202
16360
  attemptN,
@@ -16211,33 +16369,8 @@ async function executePiTask(claimedTask, reporter, opts) {
16211
16369
  retryable: false
16212
16370
  }
16213
16371
  };
16214
- const checkpointPath = opts.checkpointPath ?? await ensureSnapshot({
16215
- config: opts.sandboxConfig?.snapshot,
16216
- onProgress: opts.onSnapshotProgress ?? ((m) => {
16217
- process.stderr.write(`[snapshot] ${m}\n`);
16218
- })
16219
- });
16220
- const mainRepoForRepair = findMainWorktree();
16221
- try {
16222
- execFileSync("git", [
16223
- "-C",
16224
- mainRepoForRepair,
16225
- "worktree",
16226
- "repair",
16227
- "--relative-paths"
16228
- ], { stdio: "pipe" });
16229
- } catch {}
16372
+ let reporterOpen = opts.reporterAlreadyOpened ?? false;
16230
16373
  let managed = null;
16231
- managed = await resumeVm({
16232
- checkpointPath,
16233
- agentName: opts.agentName,
16234
- mountPath,
16235
- extraAllowedHosts: opts.extraAllowedHosts,
16236
- sandboxConfig: opts.sandboxConfig
16237
- });
16238
- const diaryId = task.diaryId ?? "";
16239
- const taskTeamId = task.teamId ?? "";
16240
- let reporterOpen = false;
16241
16374
  let session = null;
16242
16375
  let subagentHandle = null;
16243
16376
  const finalUsage = emptyUsage(opts.provider, opts.model);
@@ -16256,41 +16389,103 @@ async function executePiTask(claimedTask, reporter, opts) {
16256
16389
  retryable: false
16257
16390
  }
16258
16391
  });
16392
+ let onTurnEvent;
16393
+ if (opts.makeOnTurnEvent) try {
16394
+ onTurnEvent = opts.makeOnTurnEvent(claimedTask);
16395
+ } catch (err) {
16396
+ process.stderr.write(`[emit] makeOnTurnEvent threw: ${err instanceof Error ? err.message : String(err)}\n`);
16397
+ onTurnEvent = noopTurnEventHandler;
16398
+ }
16399
+ else onTurnEvent = opts.onTurnEvent ?? noopTurnEventHandler;
16400
+ const emit = (kind, payload) => {
16401
+ try {
16402
+ onTurnEvent(kind, summarizePayloadForLog(kind, payload));
16403
+ } catch (err) {
16404
+ process.stderr.write(`[emit] onTurnEvent threw for kind="${kind}": ${err instanceof Error ? err.message : String(err)}\n`);
16405
+ }
16406
+ return reporter.record({
16407
+ kind,
16408
+ payload
16409
+ });
16410
+ };
16411
+ const emitError = async (phase, message, extra = {}) => {
16412
+ await emit("error", {
16413
+ phase,
16414
+ message,
16415
+ ...extra
16416
+ });
16417
+ };
16259
16418
  try {
16260
- const mainRepo = findMainWorktree();
16261
- activateAgentEnv(managed.credentials.agentEnv, mainRepo);
16262
- await reporter.open({
16419
+ if (!opts.reporterAlreadyOpened) await reporter.open({
16263
16420
  taskId: task.id,
16264
16421
  attemptN
16265
16422
  });
16266
16423
  reporterOpen = true;
16267
- let onTurnEvent;
16268
- if (opts.makeOnTurnEvent) try {
16269
- onTurnEvent = opts.makeOnTurnEvent(claimedTask);
16424
+ let checkpointPath;
16425
+ try {
16426
+ checkpointPath = opts.checkpointPath ?? (opts.resolveCheckpointPath ? await opts.resolveCheckpointPath() : await ensureSnapshot({
16427
+ config: opts.sandboxConfig?.snapshot,
16428
+ onProgress: opts.onSnapshotProgress ?? ((m) => {
16429
+ process.stderr.write(`[snapshot] ${m}\n`);
16430
+ })
16431
+ }));
16432
+ } catch (err) {
16433
+ const message = err instanceof Error ? err.message : String(err);
16434
+ await emitError("snapshot", message);
16435
+ return makeFailedOutput("snapshot_failed", message);
16436
+ }
16437
+ try {
16438
+ workspace = prepareTaskWorkspace(task, requestedMountPath, executionPlan);
16439
+ mountPath = workspace.mountPath;
16440
+ cwdPath = workspace.cwdPath;
16270
16441
  } catch (err) {
16271
- process.stderr.write(`[emit] makeOnTurnEvent threw: ${err instanceof Error ? err.message : String(err)}\n`);
16272
- onTurnEvent = noopTurnEventHandler;
16442
+ const message = err instanceof Error ? err.message : String(err);
16443
+ await emitError("worktree_setup", message);
16444
+ return makeFailedOutput("worktree_setup_failed", message);
16273
16445
  }
16274
- else onTurnEvent = opts.onTurnEvent ?? noopTurnEventHandler;
16275
- const emit = (kind, payload) => {
16446
+ try {
16447
+ const mainRepoForRepair = findMainWorktree();
16276
16448
  try {
16277
- onTurnEvent(kind, summarizePayloadForLog(kind, payload));
16278
- } catch (err) {
16279
- process.stderr.write(`[emit] onTurnEvent threw for kind="${kind}": ${err instanceof Error ? err.message : String(err)}\n`);
16280
- }
16281
- return reporter.record({
16282
- kind,
16283
- payload
16449
+ execFileSync("git", [
16450
+ "-C",
16451
+ mainRepoForRepair,
16452
+ "worktree",
16453
+ "repair",
16454
+ "--relative-paths"
16455
+ ], { stdio: "pipe" });
16456
+ } catch {}
16457
+ } catch (err) {
16458
+ const message = err instanceof Error ? err.message : String(err);
16459
+ await emitError("worktree_setup", message);
16460
+ return makeFailedOutput("worktree_setup_failed", message);
16461
+ }
16462
+ try {
16463
+ managed = await resumeVm({
16464
+ checkpointPath,
16465
+ agentName: opts.agentName,
16466
+ mountPath,
16467
+ extraAllowedHosts: opts.extraAllowedHosts,
16468
+ sandboxConfig: opts.sandboxConfig
16284
16469
  });
16285
- };
16470
+ } catch (err) {
16471
+ const message = err instanceof Error ? err.message : String(err);
16472
+ await emitError("vm_resume", message);
16473
+ return makeFailedOutput("vm_resume_failed", message);
16474
+ }
16475
+ const diaryId = task.diaryId ?? "";
16476
+ const taskTeamId = task.teamId ?? "";
16477
+ const mainRepo = findMainWorktree();
16478
+ activateAgentEnv(managed.credentials.agentEnv, mainRepo);
16479
+ const activeWorkspace = workspace;
16480
+ if (!activeWorkspace) throw new Error("task workspace not prepared");
16286
16481
  await emit("info", {
16287
16482
  event: "execute_start",
16288
16483
  taskType: task.taskType,
16289
16484
  teamId: task.teamId,
16290
16485
  provider: opts.provider,
16291
16486
  model: opts.model,
16292
- workspaceMode: workspace.mode,
16293
- workspaceBranch: workspace.branch
16487
+ workspaceMode: activeWorkspace.mode,
16488
+ workspaceBranch: activeWorkspace.branch
16294
16489
  });
16295
16490
  let taskPrompt;
16296
16491
  try {
@@ -16298,8 +16493,8 @@ async function executePiTask(claimedTask, reporter, opts) {
16298
16493
  diaryId,
16299
16494
  taskId: task.id,
16300
16495
  workspace: {
16301
- mode: workspace.mode,
16302
- branch: workspace.branch
16496
+ mode: activeWorkspace.mode,
16497
+ branch: activeWorkspace.branch
16303
16498
  },
16304
16499
  extras: opts.promptExtras
16305
16500
  });
@@ -16351,7 +16546,7 @@ async function executePiTask(claimedTask, reporter, opts) {
16351
16546
  getTeamId: () => taskTeamId,
16352
16547
  getSessionErrors: () => [],
16353
16548
  clearSessionErrors: () => {},
16354
- getHostCwd: () => mountPath,
16549
+ getHostCwd: () => cwdPath,
16355
16550
  hostExecBaseEnv: new Set([...HOST_EXEC_DEFAULT_BASE_ENV, ...Object.keys(managed.credentials.agentEnv)]),
16356
16551
  hostExecAutoApprove: opts.hostExecAutoApprove ?? opts.sandboxConfig?.hostExec?.autoApprove ?? false,
16357
16552
  getTaskContext: () => ({
@@ -16379,6 +16574,7 @@ async function executePiTask(claimedTask, reporter, opts) {
16379
16574
  if (taskTypeUsesSubagents(task.taskType)) {
16380
16575
  subagentHandle = createSubagentTool({
16381
16576
  mountPath,
16577
+ cwdPath,
16382
16578
  piAuthDir,
16383
16579
  modelHandle,
16384
16580
  agentName: opts.agentName,
@@ -16387,12 +16583,14 @@ async function executePiTask(claimedTask, reporter, opts) {
16387
16583
  parentTaskId: task.id,
16388
16584
  parentTaskType: task.taskType,
16389
16585
  parentAttemptN: attemptN,
16586
+ contractRegistry: opts.subagentContractRegistry,
16390
16587
  parentCancelSignal: reporter.cancelSignal
16391
16588
  });
16392
16589
  parentSubagentTools.push(subagentHandle.tool);
16393
16590
  }
16394
16591
  session = await buildAgentSession({
16395
16592
  mountPath,
16593
+ cwdPath,
16396
16594
  piAuthDir,
16397
16595
  modelHandle,
16398
16596
  agentName: opts.agentName,
@@ -16477,6 +16675,10 @@ async function executePiTask(claimedTask, reporter, opts) {
16477
16675
  is_error: event.isError,
16478
16676
  result: event.isError ? truncateForWire(event.result) : void 0
16479
16677
  }));
16678
+ if (event.isError) track(emitError("tool_call_error", describeToolErrorMessage(event.result), {
16679
+ tool: event.toolName,
16680
+ result: truncateForWire(event.result)
16681
+ }));
16480
16682
  if (maxBashTimeouts > 0 && event.toolName === "bash" && event.isError && isBashTimeoutResult(event.result)) {
16481
16683
  bashTimeoutCount += 1;
16482
16684
  if (bashTimeoutCount >= maxBashTimeouts) triggerCapAbort("max_bash_timeouts_exceeded", `Aborted after ${bashTimeoutCount} bash timeouts in this attempt (cap ${maxBashTimeouts}).`);
@@ -16632,7 +16834,7 @@ async function executePiTask(claimedTask, reporter, opts) {
16632
16834
  }
16633
16835
  }
16634
16836
  if (managed) await managed.vm.close();
16635
- try {
16837
+ if (workspace) try {
16636
16838
  workspace.cleanup();
16637
16839
  } catch (err) {
16638
16840
  const detail = err instanceof Error ? err.message : String(err);
@@ -16743,6 +16945,23 @@ function truncateForWire(value) {
16743
16945
  };
16744
16946
  }
16745
16947
  }
16948
+ function describeToolErrorMessage(result) {
16949
+ if (typeof result === "string" && result.trim().length > 0) return result.trim();
16950
+ if (result && typeof result === "object") {
16951
+ const content = result.content;
16952
+ if (Array.isArray(content)) {
16953
+ for (const item of content) if (item && typeof item === "object" && typeof item.text === "string") {
16954
+ const text = item.text.trim();
16955
+ if (text.length > 0) return text;
16956
+ }
16957
+ }
16958
+ }
16959
+ try {
16960
+ return JSON.stringify(truncateForWire(result));
16961
+ } catch {
16962
+ return "Tool call failed";
16963
+ }
16964
+ }
16746
16965
  //#endregion
16747
16966
  //#region src/config.ts
16748
16967
  function loadConfig() {
@@ -17619,9 +17838,15 @@ async function runPolling(opts) {
17619
17838
  maxPollIntervalMs
17620
17839
  }, "agent-daemon.starting");
17621
17840
  const outputs = [];
17841
+ const subagentContractRegistry = createSubagentContractRegistry([{
17842
+ name: "judge_eval_variant_result",
17843
+ description: "Per-variant grading result produced by a subagent of judge_eval_variant: scores against the shared rubric, composite, and a 1-3 sentence verdict for a single variant.",
17844
+ parametersSchema: JudgeEvalVariantResult
17845
+ }]);
17622
17846
  try {
17623
17847
  const executeTask = createPiTaskExecutor({
17624
17848
  agentName: common.agent,
17849
+ subagentContractRegistry,
17625
17850
  mountPath: sandbox.rootDir,
17626
17851
  provider: common.provider,
17627
17852
  model: common.model,
@@ -17667,11 +17892,19 @@ async function runPolling(opts) {
17667
17892
  executeTask: async (claimedTask, reporter) => {
17668
17893
  const executionPlan = executionPlans.getOrCreate(claimedTask);
17669
17894
  const sessionDescriptor = executionPlan.descriptor;
17670
- const expired = slotRegistry.reapExpiredSlots();
17671
- if (expired.length > 0) rootLogger.info({
17672
- expiredCount: expired.length,
17673
- slotKeys: expired.map((item) => item.slot.slotKey)
17674
- }, "agent-daemon.daemon_slots_reaped");
17895
+ let expired;
17896
+ try {
17897
+ expired = slotRegistry.reapExpiredSlots();
17898
+ if (expired.length > 0) rootLogger.info({
17899
+ expiredCount: expired.length,
17900
+ slotKeys: expired.map((item) => item.slot.slotKey)
17901
+ }, "agent-daemon.daemon_slots_reaped");
17902
+ } catch (err) {
17903
+ rootLogger.error({
17904
+ phase: "daemon_slot_reap",
17905
+ err: err instanceof Error ? err.message : String(err)
17906
+ }, "agent-daemon.daemon_slot_reap_failed");
17907
+ }
17675
17908
  rootLogger.debug({
17676
17909
  taskId: claimedTask.task.id,
17677
17910
  taskType: claimedTask.task.taskType,
@@ -17866,9 +18099,15 @@ async function runOnce(argv) {
17866
18099
  process.on("SIGTERM", () => {
17867
18100
  onSignal("SIGTERM");
17868
18101
  });
18102
+ const subagentContractRegistry = createSubagentContractRegistry([{
18103
+ name: "judge_eval_variant_result",
18104
+ description: "Per-variant grading result produced by a subagent of judge_eval_variant: scores against the shared rubric, composite, and a 1-3 sentence verdict for a single variant.",
18105
+ parametersSchema: JudgeEvalVariantResult
18106
+ }]);
17869
18107
  try {
17870
18108
  const rawExecuteTask = createPiTaskExecutor({
17871
18109
  agentName: opts.agent,
18110
+ subagentContractRegistry,
17872
18111
  mountPath: sandbox.rootDir,
17873
18112
  provider: opts.provider,
17874
18113
  model: opts.model,
@@ -17879,11 +18118,18 @@ async function runOnce(argv) {
17879
18118
  maxBashTimeouts: opts.maxBashTimeouts
17880
18119
  });
17881
18120
  const executeTask = async (claimedTask, reporter) => {
17882
- const expired = slotRegistry.reapExpiredSlots();
17883
- if (expired.length > 0) rootLogger.info({
17884
- expiredCount: expired.length,
17885
- slotKeys: expired.map((item) => item.slot.slotKey)
17886
- }, "agent-daemon.daemon_slots_reaped");
18121
+ try {
18122
+ const expired = slotRegistry.reapExpiredSlots();
18123
+ if (expired.length > 0) rootLogger.info({
18124
+ expiredCount: expired.length,
18125
+ slotKeys: expired.map((item) => item.slot.slotKey)
18126
+ }, "agent-daemon.daemon_slots_reaped");
18127
+ } catch (err) {
18128
+ rootLogger.error({
18129
+ phase: "daemon_slot_reap",
18130
+ err: err instanceof Error ? err.message : String(err)
18131
+ }, "agent-daemon.daemon_slot_reap_failed");
18132
+ }
17887
18133
  const executionPlan = executionPlans.getOrCreate(claimedTask);
17888
18134
  if (executionPlan.slotKey && executionPlan.sessionPersistence) slotRegistry.beginSlot({
17889
18135
  ...slotIdentity,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
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.",
@@ -33,9 +33,9 @@
33
33
  "@opentelemetry/semantic-conventions": "^1.39.0",
34
34
  "pino": "^10.3.1",
35
35
  "pino-pretty": "^13.1.3",
36
- "@themoltnet/pi-extension": "0.17.0",
37
- "@themoltnet/agent-runtime": "0.15.1",
38
- "@themoltnet/sdk": "0.102.0"
36
+ "@themoltnet/agent-runtime": "0.16.0",
37
+ "@themoltnet/sdk": "0.102.0",
38
+ "@themoltnet/pi-extension": "0.18.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsx": "^4.7.0",
@@ -43,9 +43,9 @@
43
43
  "vite": "^8.0.0",
44
44
  "vitest": "^3.0.0",
45
45
  "@moltnet/bootstrap": "0.1.0",
46
+ "@moltnet/crypto-service": "0.1.0",
46
47
  "@moltnet/database": "0.1.0",
47
- "@moltnet/tasks": "0.1.0",
48
- "@moltnet/crypto-service": "0.1.0"
48
+ "@moltnet/tasks": "0.1.0"
49
49
  },
50
50
  "nx": {
51
51
  "tags": [