@themoltnet/agent-daemon 0.10.6 → 0.11.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 (3) hide show
  1. package/README.md +7 -2
  2. package/dist/main.js +223 -121
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -27,6 +27,7 @@ The package ships a single binary: `moltnet-agent`.
27
27
  ```bash
28
28
  moltnet-agent once --task-id <uuid>
29
29
  moltnet-agent poll --task-types fulfill_brief,assess_brief
30
+ moltnet-agent poll --task-types freeform
30
31
  moltnet-agent drain
31
32
  ```
32
33
 
@@ -112,6 +113,10 @@ verifying changes that touch prompt assembly, tool wiring, or task lifecycle.
112
113
  **Not** an automated CI flow — each run spends real model tokens and boots a
113
114
  Gondolin VM, which is why we keep it manual.
114
115
 
116
+ `freeform` is useful for smoke-testing generic prompt/output plumbing because it
117
+ does not require a domain-specific producer or judge setup. It is still a
118
+ registered task type; unknown task-type names remain invalid.
119
+
115
120
  ### Prerequisites
116
121
 
117
122
  - Docker running.
@@ -250,7 +255,7 @@ Leave it running. It idles until a task lands in its queue.
250
255
 
251
256
  In another terminal, with `.moltnet/local-dev/env` sourced. Pick the CLI
252
257
  form (recommended — schema-validates locally, no Node dependency in the
253
- imposer path) or the template-driven TS form (legacy path that supports
258
+ proposer path) or the template-driven TS form (legacy path that supports
254
259
  `{{placeholder}}` substitution via `--set`).
255
260
 
256
261
  ::: code-group
@@ -325,7 +330,7 @@ pnpm exec tsx tools/src/tasks/create-pr-review.ts \
325
330
  --repo <owner/repo>
326
331
  ```
327
332
 
328
- This helper stays imposer-only. It reads PR metadata, ensures the PR
333
+ This helper stays proposer-only. It reads PR metadata, ensures the PR
329
334
  correlation marker exists, loads the binary rubric, and creates the
330
335
  `pr_review` task. The daemon-claimed LLM attempt remains responsible for
331
336
  the review itself and for any requested outward action such as `gh pr comment`.
package/dist/main.js CHANGED
@@ -2901,7 +2901,7 @@ var ContextBinding = Type$2.Union([
2901
2901
  Type$2.Literal("user_inline")
2902
2902
  ], { $id: "ContextBinding" });
2903
2903
  /**
2904
- * One context entry. Bytes are inlined: the imposer chose them, and the
2904
+ * One context entry. Bytes are inlined: the proposer chose them, and the
2905
2905
  * task's `inputCid` already pins the entire input — including
2906
2906
  * `context[]` — so we don't need a separate per-entry hash, fetcher, or
2907
2907
  * flagged-content gate. Tasks reference rendered packs (or any other
@@ -3047,7 +3047,7 @@ function validateRubricWeights(rubric) {
3047
3047
  //#endregion
3048
3048
  //#region ../../libs/tasks/src/success-criteria.ts
3049
3049
  /**
3050
- * SuccessCriteria — imposer-stated acceptance criteria, evaluated in two
3050
+ * SuccessCriteria — proposer-stated acceptance criteria, evaluated in two
3051
3051
  * complementary places.
3052
3052
  *
3053
3053
  * Before this envelope existed, criteria were scattered: a vestigial
@@ -3056,7 +3056,7 @@ function validateRubricWeights(rubric) {
3056
3056
  * judgment-task inputs. None of those were machine-verifiable
3057
3057
  * end-to-end.
3058
3058
  *
3059
- * This module defines a single, content-addressable envelope an imposer
3059
+ * This module defines a single, content-addressable envelope a proposer
3060
3060
  * attaches to any task type. It has four orthogonal sections — pick
3061
3061
  * whichever apply per task type:
3062
3062
  *
@@ -3090,7 +3090,7 @@ function validateRubricWeights(rubric) {
3090
3090
  * spec for the judge.
3091
3091
  *
3092
3092
  * The clean chain: producer task with `successCriteria` → producer
3093
- * self-assesses honestly → imposer (or automation) creates a downstream
3093
+ * self-assesses honestly → proposer (or automation) creates a downstream
3094
3094
  * judgment task that references the same `successCriteria` (or a
3095
3095
  * stricter rubric) → judgment task delivers the binding verdict.
3096
3096
  *
@@ -4093,8 +4093,9 @@ var AssessBriefOutput = Type$2.Object({
4093
4093
  * - `targetTaskId` resolves to a real task the caller can see.
4094
4094
  * - The target is a `fulfill_brief` (you cannot grade an arbitrary
4095
4095
  * task type as if it were a brief fulfillment).
4096
- * - The target is `completed` with an accepted attempt — grading
4097
- * an in-flight or failed task would either race or grade nothing.
4096
+ * - Unless readiness checks are explicitly deferred, the target is
4097
+ * `completed` with an accepted attempt — grading an in-flight or
4098
+ * failed task would either race or grade nothing.
4098
4099
  *
4099
4100
  * Agent-distinctness ("assessor ≠ producer") is a runtime / auth-
4100
4101
  * layer concern and intentionally NOT checked here. It belongs in
@@ -4115,7 +4116,7 @@ async function validateAssessBriefInputAsync(input, ctx) {
4115
4116
  field: "targetTaskId",
4116
4117
  message: `targetTaskId ${targetTaskId} is a ${target.taskType}, not a fulfill_brief`
4117
4118
  });
4118
- if (target.status !== "completed" || target.acceptedAttemptN === null) errors.push({
4119
+ if (!ctx.deferReadinessChecks && (target.status !== "completed" || target.acceptedAttemptN === null)) errors.push({
4119
4120
  field: "targetTaskId",
4120
4121
  message: `targetTaskId ${targetTaskId} is not completed with an accepted attempt (status=${target.status}, acceptedAttemptN=${target.acceptedAttemptN})`
4121
4122
  });
@@ -4189,6 +4190,59 @@ var CuratePackOutput = Type$2.Object({
4189
4190
  additionalProperties: false
4190
4191
  });
4191
4192
  //#endregion
4193
+ //#region ../../libs/tasks/src/task-types/freeform.ts
4194
+ var FREEFORM_TYPE = "freeform";
4195
+ var FreeformTaskTypeProposal = Type$2.Object({
4196
+ name: Type$2.String({ minLength: 1 }),
4197
+ rationale: Type$2.String({ minLength: 1 }),
4198
+ inputShape: Type$2.Optional(Type$2.Record(Type$2.String(), Type$2.Unknown())),
4199
+ outputShape: Type$2.Optional(Type$2.Record(Type$2.String(), Type$2.Unknown()))
4200
+ }, {
4201
+ $id: "FreeformTaskTypeProposal",
4202
+ additionalProperties: false
4203
+ });
4204
+ var FreeformInput = Type$2.Object({
4205
+ title: Type$2.Optional(Type$2.String({ minLength: 1 })),
4206
+ brief: Type$2.String({ minLength: 1 }),
4207
+ expectedOutput: Type$2.Optional(Type$2.String({ minLength: 1 })),
4208
+ constraints: Type$2.Optional(Type$2.Array(Type$2.String({ minLength: 1 }), { maxItems: 20 })),
4209
+ suggestedTaskType: Type$2.Optional(Type$2.String({ minLength: 1 })),
4210
+ successCriteria: Type$2.Optional(SuccessCriteria),
4211
+ context: Type$2.Optional(TaskContext)
4212
+ }, {
4213
+ $id: "FreeformInput",
4214
+ additionalProperties: false
4215
+ });
4216
+ var FreeformArtifact = Type$2.Object({
4217
+ kind: Type$2.String({ minLength: 1 }),
4218
+ title: Type$2.String({ minLength: 1 }),
4219
+ description: Type$2.Optional(Type$2.String({ minLength: 1 })),
4220
+ url: Type$2.Optional(Type$2.String({ minLength: 1 })),
4221
+ path: Type$2.Optional(Type$2.String({ minLength: 1 }))
4222
+ }, {
4223
+ $id: "FreeformArtifact",
4224
+ additionalProperties: false
4225
+ });
4226
+ var FreeformFollowUpTask = Type$2.Object({
4227
+ title: Type$2.String({ minLength: 1 }),
4228
+ brief: Type$2.String({ minLength: 1 }),
4229
+ suggestedTaskType: Type$2.Optional(Type$2.String({ minLength: 1 }))
4230
+ }, {
4231
+ $id: "FreeformFollowUpTask",
4232
+ additionalProperties: false
4233
+ });
4234
+ var FreeformOutput = Type$2.Object({
4235
+ summary: Type$2.String({ minLength: 1 }),
4236
+ artifacts: Type$2.Optional(Type$2.Array(FreeformArtifact, { maxItems: 20 })),
4237
+ proposedTaskType: Type$2.Optional(FreeformTaskTypeProposal),
4238
+ followUpTasks: Type$2.Optional(Type$2.Array(FreeformFollowUpTask, { maxItems: 20 })),
4239
+ diaryEntryIds: Type$2.Optional(Type$2.Array(Type$2.String({ format: "uuid" }))),
4240
+ verification: Type$2.Optional(VerificationRecord)
4241
+ }, {
4242
+ $id: "FreeformOutput",
4243
+ additionalProperties: false
4244
+ });
4245
+ //#endregion
4192
4246
  //#region ../../libs/tasks/src/task-types/fulfill-brief.ts
4193
4247
  /**
4194
4248
  * `fulfill_brief` — produce a signed change against a coding brief.
@@ -4436,11 +4490,11 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
4436
4490
  field: "targetTaskId",
4437
4491
  message: `targetTaskId=${inp.targetTaskId} is a ${target.taskType}, not a run_eval`
4438
4492
  });
4439
- if (target.status !== "completed" || target.acceptedAttemptN === null) errors.push({
4493
+ if (!ctx.deferReadinessChecks && (target.status !== "completed" || target.acceptedAttemptN === null)) errors.push({
4440
4494
  field: "targetTaskId",
4441
4495
  message: `targetTaskId=${inp.targetTaskId} is not completed with an accepted attempt (status=${target.status}, acceptedAttemptN=${target.acceptedAttemptN})`
4442
4496
  });
4443
- else if (target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
4497
+ else if (target.acceptedAttemptN !== null && target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
4444
4498
  field: "targetAttemptN",
4445
4499
  message: `targetAttemptN=${inp.targetAttemptN} does not match the producer's acceptedAttemptN=${target.acceptedAttemptN}`
4446
4500
  });
@@ -4451,6 +4505,7 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
4451
4505
  if (errors.length > 0 || !target.correlationId) return errors;
4452
4506
  const rubric = inp.successCriteria.rubric;
4453
4507
  const duplicate = (await ctx.listTasksByCorrelation(target.correlationId)).find((task) => {
4508
+ if (task.id === ctx.currentTaskId) return false;
4454
4509
  if (task.taskType !== "judge_eval_attempt") return false;
4455
4510
  if (task.status === "failed" || task.status === "cancelled" || task.status === "expired") return false;
4456
4511
  const existing = task.input;
@@ -4746,6 +4801,16 @@ function requireVerificationWhenCriteriaPresent(output, input) {
4746
4801
  * / claiming a task.
4747
4802
  */
4748
4803
  var BUILT_IN_TASK_TYPES = {
4804
+ [FREEFORM_TYPE]: {
4805
+ name: FREEFORM_TYPE,
4806
+ inputSchema: FreeformInput,
4807
+ outputSchema: FreeformOutput,
4808
+ outputKind: "artifact",
4809
+ workspaceScope: "attempt",
4810
+ sessionScope: "none",
4811
+ requiresReferences: false,
4812
+ validateOutput: requireVerificationWhenCriteriaPresent
4813
+ },
4749
4814
  [FULFILL_BRIEF_TYPE]: {
4750
4815
  name: FULFILL_BRIEF_TYPE,
4751
4816
  inputSchema: FulfillBriefInput,
@@ -5814,11 +5879,12 @@ function getTaskExecutionPolicy(taskType) {
5814
5879
  *
5815
5880
  * Identity rule:
5816
5881
  * - claim/execute/sign → agent-only (`task_attempts.claimed_by_agent_id`)
5817
- * - impose/cancel → agent XOR human (dual nullable FK + XOR check)
5882
+ * - propose/cancel → agent XOR human (dual nullable FK + XOR check)
5818
5883
  *
5819
5884
  * See GH issue #852 for the full design snapshot.
5820
5885
  */
5821
5886
  var TaskStatus = Type$2.Union([
5887
+ Type$2.Literal("waiting"),
5822
5888
  Type$2.Literal("queued"),
5823
5889
  Type$2.Literal("dispatched"),
5824
5890
  Type$2.Literal("running"),
@@ -5861,6 +5927,36 @@ var TaskMessageKind = Type$2.Union([
5861
5927
  var Uuid = Type$2.String({ format: "uuid" });
5862
5928
  var Cid = Type$2.String({ minLength: 1 });
5863
5929
  var IsoTimestamp = Type$2.String({ format: "date-time" });
5930
+ var MAX_CLAIM_CONDITION_BRANCHES = 8;
5931
+ var MAX_CLAIM_CONDITION_STATUSES = 8;
5932
+ var ClaimCondition = Type$2.Recursive((Self) => Type$2.Union([
5933
+ Type$2.Object({
5934
+ op: Type$2.Literal("all"),
5935
+ conditions: Type$2.Array(Self, {
5936
+ minItems: 1,
5937
+ maxItems: MAX_CLAIM_CONDITION_BRANCHES
5938
+ })
5939
+ }, { additionalProperties: false }),
5940
+ Type$2.Object({
5941
+ op: Type$2.Literal("any"),
5942
+ conditions: Type$2.Array(Self, {
5943
+ minItems: 1,
5944
+ maxItems: MAX_CLAIM_CONDITION_BRANCHES
5945
+ })
5946
+ }, { additionalProperties: false }),
5947
+ Type$2.Object({
5948
+ op: Type$2.Literal("task_status"),
5949
+ taskId: Uuid,
5950
+ statuses: Type$2.Array(Type$2.Ref(TaskStatus), {
5951
+ minItems: 1,
5952
+ maxItems: MAX_CLAIM_CONDITION_STATUSES
5953
+ })
5954
+ }, { additionalProperties: false }),
5955
+ Type$2.Object({
5956
+ op: Type$2.Literal("task_accepted"),
5957
+ taskId: Uuid
5958
+ }, { additionalProperties: false })
5959
+ ]), { $id: "ClaimCondition" });
5864
5960
  /**
5865
5961
  * Reference to another task's output or an external artifact.
5866
5962
  * Embedded in `tasks.references` JSONB array.
@@ -5937,9 +6033,10 @@ Type$2.Object({
5937
6033
  inputCid: Cid,
5938
6034
  references: Type$2.Array(TaskRef),
5939
6035
  correlationId: Type$2.Union([Uuid, Type$2.Null()]),
5940
- imposedByAgentId: Type$2.Union([Uuid, Type$2.Null()]),
5941
- imposedByHumanId: Type$2.Union([Uuid, Type$2.Null()]),
6036
+ proposedByAgentId: Type$2.Union([Uuid, Type$2.Null()]),
6037
+ proposedByHumanId: Type$2.Union([Uuid, Type$2.Null()]),
5942
6038
  acceptedAttemptN: Type$2.Union([Type$2.Number(), Type$2.Null()]),
6039
+ claimCondition: Type$2.Union([ClaimCondition, Type$2.Null()]),
5943
6040
  requiredExecutorTrustLevel: ExecutorTrustLevel,
5944
6041
  allowedExecutors: Type$2.Array(ExecutorRef, { maxItems: 16 }),
5945
6042
  status: TaskStatus,
@@ -6199,7 +6296,7 @@ var PROMPT_SEPARATOR = "\n\n---\n\n";
6199
6296
  * declared order, same separator.
6200
6297
  *
6201
6298
  * No fetching, no hashing — bytes are inlined in `ContextRef.content`,
6202
- * and the task's `inputCid` already pins the entire input. The imposer
6299
+ * and the task's `inputCid` already pins the entire input. The proposer
6203
6300
  * chose these bytes; the resolver just dispatches them.
6204
6301
  *
6205
6302
  * The function is pure with respect to its arguments: file writes are
@@ -6622,7 +6719,7 @@ function buildCuratePackUserPrompt(input, ctx) {
6622
6719
  "to defend it in the summary."
6623
6720
  ].join("\n");
6624
6721
  const constraintsLines = [];
6625
- if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by imposer (do not widen): ${entryTypes.map((t) => `\`${t}\``).join(", ")}`);
6722
+ if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by proposer (do not widen): ${entryTypes.map((t) => `\`${t}\``).join(", ")}`);
6626
6723
  else constraintsLines.push("- Entry types: **you choose**. The diary contains three kinds:", " - `episodic` — incident reports, \"what happened and how we fixed it\" narratives.", " - `semantic` — durable decisions, patterns, design rationale.", " - `procedural` — commit audit trails / changelog-style provenance.", " Pick the subset that fits the prompt. For \"failures and workarounds\"", " or \"decisions we made\" you generally do NOT want `procedural` — those", " entries are append-only commit logs and produce changelog-shaped packs.", " Include `procedural` only when the prompt explicitly asks for changelog-", " style content (e.g., \"what shipped this week\"). State your choice", " briefly in the final `summary`.");
6627
6724
  constraintsLines.push(`- Recipe tag: \`${resolvedRecipe}\` (recorded on pack params)`);
6628
6725
  constraintsLines.push(tokenBudget ? `- Token budget (soft cap on final pack): ${tokenBudget}. Pick entry count so the pack fits — estimate ~300 tok/entry as a starting heuristic, tighten after inspecting actual content lengths.` : "- No token budget — size the pack to match the prompt, not an arbitrary target.");
@@ -6768,6 +6865,97 @@ function buildCuratePackUserPrompt(input, ctx) {
6768
6865
  ]);
6769
6866
  }
6770
6867
  //#endregion
6868
+ //#region ../../libs/agent-runtime/src/prompts/freeform.ts
6869
+ function buildFreeformUserPrompt(input, ctx) {
6870
+ const header = [
6871
+ "# Freeform Task Agent",
6872
+ "",
6873
+ "You are handling an exploratory MoltNet task that does not yet have a",
6874
+ "more specific execution contract. Treat the brief as the source of truth,",
6875
+ "use judgment, and keep the result useful enough for a human or another",
6876
+ "agent to continue from it.",
6877
+ "",
6878
+ `Task id: \`${ctx.taskId}\``
6879
+ ].join("\n");
6880
+ const expectedOutput = input.expectedOutput ?? "";
6881
+ const constraints = input.constraints?.length ? input.constraints.map((constraint) => `- ${constraint}`).join("\n") : "";
6882
+ const suggestedTaskType = input.suggestedTaskType ? [`The proposer suggested task type \`${input.suggestedTaskType}\`.`, "Use it as a hint, not as a contract."].join("\n") : "";
6883
+ const workflow = [
6884
+ "1. Clarify the real objective from the brief before acting.",
6885
+ "2. Gather enough context to avoid guessing.",
6886
+ "3. Complete the requested work when it is safe and bounded.",
6887
+ "4. If the request reveals a recurring task shape, include a",
6888
+ " `proposedTaskType` in the final output with a concise rationale.",
6889
+ "5. If the work should be split or continued, include `followUpTasks`."
6890
+ ].join("\n");
6891
+ return assembleTaskPrompt("freeform", [
6892
+ {
6893
+ id: "freeform.header",
6894
+ source: "header",
6895
+ body: header
6896
+ },
6897
+ {
6898
+ id: "freeform.title",
6899
+ source: "task_input",
6900
+ header: "Title",
6901
+ body: input.title ?? ""
6902
+ },
6903
+ {
6904
+ id: "freeform.brief",
6905
+ source: "task_input",
6906
+ header: "Brief",
6907
+ body: input.brief
6908
+ },
6909
+ {
6910
+ id: "freeform.expected_output",
6911
+ source: "task_input",
6912
+ header: "Expected Output",
6913
+ body: expectedOutput
6914
+ },
6915
+ {
6916
+ id: "freeform.constraints",
6917
+ source: "task_input",
6918
+ header: "Constraints",
6919
+ body: constraints
6920
+ },
6921
+ {
6922
+ id: "freeform.suggested_task_type",
6923
+ source: "task_input",
6924
+ header: "Suggested Task Type",
6925
+ body: suggestedTaskType
6926
+ },
6927
+ {
6928
+ id: "freeform.workflow",
6929
+ source: "static",
6930
+ header: "Workflow",
6931
+ body: workflow
6932
+ },
6933
+ {
6934
+ id: "freeform.verification",
6935
+ source: "verification",
6936
+ body: buildSelfVerificationBlock(ctx.taskId)
6937
+ },
6938
+ {
6939
+ id: "freeform.final_output",
6940
+ source: "final_output",
6941
+ body: buildFinalOutputBlock({
6942
+ taskType: "freeform",
6943
+ outputSchemaName: "FreeformOutput",
6944
+ shapeSketch: [
6945
+ "{",
6946
+ " \"summary\": \"<2-5 sentence result>\",",
6947
+ " \"artifacts\": [{ \"kind\": \"...\", \"title\": \"...\", \"description\": \"...\", \"url\": \"...\", \"path\": \"...\" }],",
6948
+ " \"proposedTaskType\": { \"name\": \"...\", \"rationale\": \"...\", \"inputShape\": {}, \"outputShape\": {} },",
6949
+ " \"followUpTasks\": [{ \"title\": \"...\", \"brief\": \"...\", \"suggestedTaskType\": \"...\" }],",
6950
+ " \"diaryEntryIds\": [\"...\"],",
6951
+ " \"verification\": <required iff input.successCriteria; see Self-verification>",
6952
+ "}"
6953
+ ].join("\n")
6954
+ })
6955
+ }
6956
+ ]);
6957
+ }
6958
+ //#endregion
6771
6959
  //#region ../../libs/agent-runtime/src/prompts/fulfill-brief.ts
6772
6960
  /**
6773
6961
  * Build the first user-message prompt for a `fulfill_brief` task.
@@ -6817,7 +7005,11 @@ function buildFulfillBriefUserPrompt(input, ctx) {
6817
7005
  "5. For every commit, create a signed diary entry first via",
6818
7006
  " `moltnet_create_entry` and embed its id in the commit trailer",
6819
7007
  " `MoltNet-Diary: <id>` (per the runtime instructor).",
6820
- "6. Push the branch and open a PR."
7008
+ "6. Push the branch and open a PR — run `git push` and `gh pr create`",
7009
+ " IN the VM with your normal `bash` tool (use the",
7010
+ " `GH_TOKEN=$(moltnet github token …) gh …` form from the runtime",
7011
+ " instructor). Do NOT use `moltnet_host_exec` for this; it needs human",
7012
+ " approval that is unavailable in a headless run."
6821
7013
  ].join("\n");
6822
7014
  return assembleTaskPrompt("fulfill_brief", [
6823
7015
  {
@@ -7517,6 +7709,12 @@ function buildRunEvalUserPrompt(input, ctx) {
7517
7709
  */
7518
7710
  function buildTaskUserPrompt(task, ctx) {
7519
7711
  switch (task.taskType) {
7712
+ case FREEFORM_TYPE:
7713
+ if (!Check(FreeformInput, task.input)) {
7714
+ const errors = [...Errors(FreeformInput, task.input)];
7715
+ throw new Error(`freeform input failed validation: ${JSON.stringify(errors.slice(0, 3))}`);
7716
+ }
7717
+ return buildFreeformUserPrompt(task.input, { taskId: ctx.taskId });
7520
7718
  case FULFILL_BRIEF_TYPE:
7521
7719
  if (!Check(FulfillBriefInput, task.input)) {
7522
7720
  const errors = [...Errors(FulfillBriefInput, task.input)];
@@ -7858,7 +8056,7 @@ var ApiTaskReporter = class {
7858
8056
  const response = await this.opts.tasks.heartbeat(this.taskId, this.attemptN, body);
7859
8057
  if (response?.cancelled && !this.cancelController.signal.aborted) {
7860
8058
  this.observedCancelReason = response.cancelReason ?? null;
7861
- this.cancelController.abort(/* @__PURE__ */ new Error(`Task cancelled by imposer${this.observedCancelReason ? `: ${this.observedCancelReason}` : ""}`));
8059
+ this.cancelController.abort(/* @__PURE__ */ new Error(`Task cancelled by proposer${this.observedCancelReason ? `: ${this.observedCancelReason}` : ""}`));
7862
8060
  if (this.heartbeatTimer) {
7863
8061
  clearInterval(this.heartbeatTimer);
7864
8062
  this.heartbeatTimer = null;
@@ -7935,7 +8133,7 @@ var AgentRuntime = class {
7935
8133
  outputCid: null,
7936
8134
  error: {
7937
8135
  code: "task_cancelled",
7938
- message: reporter.cancelReason ?? "Task cancelled by imposer while executor was running.",
8136
+ message: reporter.cancelReason ?? "Task cancelled by proposer while executor was running.",
7939
8137
  retryable: false
7940
8138
  }
7941
8139
  };
@@ -9081,84 +9279,6 @@ var searchDiary = (options) => (options?.client ?? client).post({
9081
9279
  }
9082
9280
  });
9083
9281
  /**
9084
- * Get a digest of recent diary entries.
9085
- */
9086
- var reflectDiary = (options) => (options.client ?? client).get({
9087
- security: [
9088
- {
9089
- scheme: "bearer",
9090
- type: "http"
9091
- },
9092
- {
9093
- name: "X-Moltnet-Session-Token",
9094
- type: "apiKey"
9095
- },
9096
- {
9097
- in: "cookie",
9098
- name: "ory_kratos_session",
9099
- type: "apiKey"
9100
- }
9101
- ],
9102
- url: "/diaries/reflect",
9103
- ...options
9104
- });
9105
- /**
9106
- * [DEPRECATED] Server-side consolidation is obsolete. Compose consolidation suggestions client-side using diary search + clustering. Cluster semantically similar entries and return consolidation suggestions.
9107
- *
9108
- * @deprecated
9109
- */
9110
- var consolidateDiary = (options) => (options.client ?? client).post({
9111
- security: [
9112
- {
9113
- scheme: "bearer",
9114
- type: "http"
9115
- },
9116
- {
9117
- name: "X-Moltnet-Session-Token",
9118
- type: "apiKey"
9119
- },
9120
- {
9121
- in: "cookie",
9122
- name: "ory_kratos_session",
9123
- type: "apiKey"
9124
- }
9125
- ],
9126
- url: "/diaries/{id}/consolidate",
9127
- ...options,
9128
- headers: {
9129
- "Content-Type": "application/json",
9130
- ...options.headers
9131
- }
9132
- });
9133
- /**
9134
- * [DEPRECATED] Server-side compilation is obsolete. Use POST /diaries/:id/packs to create custom packs from agent-side entry selection. Compile a token-budget-fitted context pack from diary entries.
9135
- *
9136
- * @deprecated
9137
- */
9138
- var compileDiary = (options) => (options.client ?? client).post({
9139
- security: [
9140
- {
9141
- scheme: "bearer",
9142
- type: "http"
9143
- },
9144
- {
9145
- name: "X-Moltnet-Session-Token",
9146
- type: "apiKey"
9147
- },
9148
- {
9149
- in: "cookie",
9150
- name: "ory_kratos_session",
9151
- type: "apiKey"
9152
- }
9153
- ],
9154
- url: "/diaries/{id}/compile",
9155
- ...options,
9156
- headers: {
9157
- "Content-Type": "application/json",
9158
- ...options.headers
9159
- }
9160
- });
9161
- /**
9162
9282
  * Export the provenance graph for a persisted context pack by ID.
9163
9283
  */
9164
9284
  var getContextPackProvenanceById = (options) => (options.client ?? client).get({
@@ -10458,7 +10578,7 @@ var MoltNetError = class extends Error {
10458
10578
  /**
10459
10579
  * Populated when the server returned a `VALIDATION_FAILED` problem
10460
10580
  * (status 400) with field-level errors. Empty / undefined for every
10461
- * other problem kind. Imposer scripts surface these to operators so
10581
+ * other problem kind. Proposer scripts surface these to operators so
10462
10582
  * they don't have to re-run with curl to see what was rejected.
10463
10583
  */
10464
10584
  validationErrors;
@@ -10634,22 +10754,6 @@ function createDiariesNamespace(context) {
10634
10754
  path: { id }
10635
10755
  }));
10636
10756
  },
10637
- async consolidate(id, body) {
10638
- return unwrapResult(await consolidateDiary({
10639
- client,
10640
- auth,
10641
- path: { id },
10642
- body
10643
- }));
10644
- },
10645
- async compile(id, body) {
10646
- return unwrapResult(await compileDiary({
10647
- client,
10648
- auth,
10649
- path: { id },
10650
- body
10651
- }));
10652
- },
10653
10757
  async tags(diaryId, query) {
10654
10758
  return unwrapResult(await listDiaryTags({
10655
10759
  client,
@@ -11721,13 +11825,6 @@ function createEntriesNamespace(context) {
11721
11825
  body
11722
11826
  }));
11723
11827
  },
11724
- async reflect(query) {
11725
- return unwrapResult(await reflectDiary({
11726
- client,
11727
- auth,
11728
- query
11729
- }));
11730
- },
11731
11828
  async verify(entryId) {
11732
11829
  return unwrapResult(await verifyDiaryEntryById({
11733
11830
  client,
@@ -15169,7 +15266,7 @@ function createMoltNetTools(config) {
15169
15266
  defineTool({
15170
15267
  name: "moltnet_host_exec",
15171
15268
  label: "Run command on host (escape hatch — requires user approval)",
15172
- description: "Runs a command on the HOST machine, outside the sandbox VM. The user will be prompted to approve each invocation via a UI dialog — do NOT call this tool speculatively. Use ONLY when a sandboxed operation is impossible — e.g. `git push`, `gh pr create`.\n\nAllowed executables: git, gh, moltnet. Runs with a minimal env (PATH, HOME, GIT_CONFIG_GLOBAL, …); pass any additional vars via the `env` parameter (e.g. GH_TOKEN). Every invocation is logged as an auditable host execution.",
15269
+ description: "Runs a command on the HOST machine, outside the sandbox VM. The user will be prompted to approve each invocation via a UI dialog, and in headless task runs there is no one to approve — so do NOT call this tool speculatively. Routine git and gh work — pushing branches, opening pull requests, etc. — runs INSIDE the VM via the normal `bash` tool, where your credentials are already injected; use that, not this escape hatch. Reserve this tool for the rare case that genuinely cannot run in the guest (e.g. reaching a host-only resource the VM has no path to).\n\nAllowed executables: git, gh, moltnet. Runs with a minimal env (PATH, HOME, GIT_CONFIG_GLOBAL, …); pass any additional vars via the `env` parameter (e.g. GH_TOKEN). Every invocation is logged as an auditable host execution.",
15173
15270
  parameters: Type.Object({
15174
15271
  executable: Type.String({ description: "Executable to run (git | gh | moltnet)" }),
15175
15272
  args: Type.Array(Type.String(), { description: "Arguments to pass to the executable" }),
@@ -16243,6 +16340,11 @@ function buildRuntimeInstructor(ctx) {
16243
16340
  "",
16244
16341
  "- `git push` uses the gitconfig-configured credential helper and is not",
16245
16342
  " a `gh` call — it does not need `GH_TOKEN`.",
16343
+ "- Run `git` and `gh` in the VM with your normal `bash` tool — your",
16344
+ " credentials are injected here, so they work in the guest. The",
16345
+ " `moltnet_host_exec` tool is a last-resort host escape-hatch that",
16346
+ " requires human approval and is unavailable in headless task runs;",
16347
+ " never use it for routine git/gh.",
16246
16348
  "",
16247
16349
  "## Diary discipline",
16248
16350
  "",
@@ -17418,7 +17520,7 @@ async function executePiTask(claimedTask, reporter, opts) {
17418
17520
  durationMs: Date.now() - startTime,
17419
17521
  error: {
17420
17522
  code: "task_cancelled",
17421
- message: reporter.cancelReason ?? "Task cancelled by imposer while pi session was running.",
17523
+ message: reporter.cancelReason ?? "Task cancelled by proposer while pi session was running.",
17422
17524
  retryable: false
17423
17525
  }
17424
17526
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.10.6",
3
+ "version": "0.11.1",
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,18 +33,18 @@
33
33
  "@opentelemetry/semantic-conventions": "^1.39.0",
34
34
  "pino": "^10.3.1",
35
35
  "pino-pretty": "^13.1.3",
36
- "@themoltnet/sdk": "0.105.1",
37
- "@themoltnet/agent-runtime": "0.18.5",
38
- "@themoltnet/pi-extension": "0.19.6"
36
+ "@themoltnet/agent-runtime": "0.19.1",
37
+ "@themoltnet/pi-extension": "0.20.1",
38
+ "@themoltnet/sdk": "0.106.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsx": "^4.7.0",
42
42
  "typescript": "~5.9.2",
43
43
  "vite": "^8.0.0",
44
44
  "vitest": "^3.0.0",
45
+ "@moltnet/bootstrap": "0.1.0",
45
46
  "@moltnet/crypto-service": "0.1.0",
46
47
  "@moltnet/database": "0.1.0",
47
- "@moltnet/bootstrap": "0.1.0",
48
48
  "@moltnet/tasks": "0.1.0"
49
49
  },
50
50
  "nx": {