@themoltnet/agent-daemon 0.10.5 → 0.11.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 +2 -2
  2. package/dist/main.js +52 -18
  3. package/package.json +8 -8
package/README.md CHANGED
@@ -250,7 +250,7 @@ Leave it running. It idles until a task lands in its queue.
250
250
 
251
251
  In another terminal, with `.moltnet/local-dev/env` sourced. Pick the CLI
252
252
  form (recommended — schema-validates locally, no Node dependency in the
253
- imposer path) or the template-driven TS form (legacy path that supports
253
+ proposer path) or the template-driven TS form (legacy path that supports
254
254
  `{{placeholder}}` substitution via `--set`).
255
255
 
256
256
  ::: code-group
@@ -325,7 +325,7 @@ pnpm exec tsx tools/src/tasks/create-pr-review.ts \
325
325
  --repo <owner/repo>
326
326
  ```
327
327
 
328
- This helper stays imposer-only. It reads PR metadata, ensures the PR
328
+ This helper stays proposer-only. It reads PR metadata, ensures the PR
329
329
  correlation marker exists, loads the binary rubric, and creates the
330
330
  `pr_review` task. The daemon-claimed LLM attempt remains responsible for
331
331
  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
  });
@@ -4436,11 +4437,11 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
4436
4437
  field: "targetTaskId",
4437
4438
  message: `targetTaskId=${inp.targetTaskId} is a ${target.taskType}, not a run_eval`
4438
4439
  });
4439
- if (target.status !== "completed" || target.acceptedAttemptN === null) errors.push({
4440
+ if (!ctx.deferReadinessChecks && (target.status !== "completed" || target.acceptedAttemptN === null)) errors.push({
4440
4441
  field: "targetTaskId",
4441
4442
  message: `targetTaskId=${inp.targetTaskId} is not completed with an accepted attempt (status=${target.status}, acceptedAttemptN=${target.acceptedAttemptN})`
4442
4443
  });
4443
- else if (target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
4444
+ else if (target.acceptedAttemptN !== null && target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
4444
4445
  field: "targetAttemptN",
4445
4446
  message: `targetAttemptN=${inp.targetAttemptN} does not match the producer's acceptedAttemptN=${target.acceptedAttemptN}`
4446
4447
  });
@@ -4451,6 +4452,7 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
4451
4452
  if (errors.length > 0 || !target.correlationId) return errors;
4452
4453
  const rubric = inp.successCriteria.rubric;
4453
4454
  const duplicate = (await ctx.listTasksByCorrelation(target.correlationId)).find((task) => {
4455
+ if (task.id === ctx.currentTaskId) return false;
4454
4456
  if (task.taskType !== "judge_eval_attempt") return false;
4455
4457
  if (task.status === "failed" || task.status === "cancelled" || task.status === "expired") return false;
4456
4458
  const existing = task.input;
@@ -5814,11 +5816,12 @@ function getTaskExecutionPolicy(taskType) {
5814
5816
  *
5815
5817
  * Identity rule:
5816
5818
  * - claim/execute/sign → agent-only (`task_attempts.claimed_by_agent_id`)
5817
- * - impose/cancel → agent XOR human (dual nullable FK + XOR check)
5819
+ * - propose/cancel → agent XOR human (dual nullable FK + XOR check)
5818
5820
  *
5819
5821
  * See GH issue #852 for the full design snapshot.
5820
5822
  */
5821
5823
  var TaskStatus = Type$2.Union([
5824
+ Type$2.Literal("waiting"),
5822
5825
  Type$2.Literal("queued"),
5823
5826
  Type$2.Literal("dispatched"),
5824
5827
  Type$2.Literal("running"),
@@ -5861,6 +5864,36 @@ var TaskMessageKind = Type$2.Union([
5861
5864
  var Uuid = Type$2.String({ format: "uuid" });
5862
5865
  var Cid = Type$2.String({ minLength: 1 });
5863
5866
  var IsoTimestamp = Type$2.String({ format: "date-time" });
5867
+ var MAX_CLAIM_CONDITION_BRANCHES = 8;
5868
+ var MAX_CLAIM_CONDITION_STATUSES = 8;
5869
+ var ClaimCondition = Type$2.Recursive((Self) => Type$2.Union([
5870
+ Type$2.Object({
5871
+ op: Type$2.Literal("all"),
5872
+ conditions: Type$2.Array(Self, {
5873
+ minItems: 1,
5874
+ maxItems: MAX_CLAIM_CONDITION_BRANCHES
5875
+ })
5876
+ }, { additionalProperties: false }),
5877
+ Type$2.Object({
5878
+ op: Type$2.Literal("any"),
5879
+ conditions: Type$2.Array(Self, {
5880
+ minItems: 1,
5881
+ maxItems: MAX_CLAIM_CONDITION_BRANCHES
5882
+ })
5883
+ }, { additionalProperties: false }),
5884
+ Type$2.Object({
5885
+ op: Type$2.Literal("task_status"),
5886
+ taskId: Uuid,
5887
+ statuses: Type$2.Array(Type$2.Ref(TaskStatus), {
5888
+ minItems: 1,
5889
+ maxItems: MAX_CLAIM_CONDITION_STATUSES
5890
+ })
5891
+ }, { additionalProperties: false }),
5892
+ Type$2.Object({
5893
+ op: Type$2.Literal("task_accepted"),
5894
+ taskId: Uuid
5895
+ }, { additionalProperties: false })
5896
+ ]), { $id: "ClaimCondition" });
5864
5897
  /**
5865
5898
  * Reference to another task's output or an external artifact.
5866
5899
  * Embedded in `tasks.references` JSONB array.
@@ -5937,9 +5970,10 @@ Type$2.Object({
5937
5970
  inputCid: Cid,
5938
5971
  references: Type$2.Array(TaskRef),
5939
5972
  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()]),
5973
+ proposedByAgentId: Type$2.Union([Uuid, Type$2.Null()]),
5974
+ proposedByHumanId: Type$2.Union([Uuid, Type$2.Null()]),
5942
5975
  acceptedAttemptN: Type$2.Union([Type$2.Number(), Type$2.Null()]),
5976
+ claimCondition: Type$2.Union([ClaimCondition, Type$2.Null()]),
5943
5977
  requiredExecutorTrustLevel: ExecutorTrustLevel,
5944
5978
  allowedExecutors: Type$2.Array(ExecutorRef, { maxItems: 16 }),
5945
5979
  status: TaskStatus,
@@ -6199,7 +6233,7 @@ var PROMPT_SEPARATOR = "\n\n---\n\n";
6199
6233
  * declared order, same separator.
6200
6234
  *
6201
6235
  * No fetching, no hashing — bytes are inlined in `ContextRef.content`,
6202
- * and the task's `inputCid` already pins the entire input. The imposer
6236
+ * and the task's `inputCid` already pins the entire input. The proposer
6203
6237
  * chose these bytes; the resolver just dispatches them.
6204
6238
  *
6205
6239
  * The function is pure with respect to its arguments: file writes are
@@ -6622,7 +6656,7 @@ function buildCuratePackUserPrompt(input, ctx) {
6622
6656
  "to defend it in the summary."
6623
6657
  ].join("\n");
6624
6658
  const constraintsLines = [];
6625
- if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by imposer (do not widen): ${entryTypes.map((t) => `\`${t}\``).join(", ")}`);
6659
+ if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by proposer (do not widen): ${entryTypes.map((t) => `\`${t}\``).join(", ")}`);
6626
6660
  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
6661
  constraintsLines.push(`- Recipe tag: \`${resolvedRecipe}\` (recorded on pack params)`);
6628
6662
  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.");
@@ -7858,7 +7892,7 @@ var ApiTaskReporter = class {
7858
7892
  const response = await this.opts.tasks.heartbeat(this.taskId, this.attemptN, body);
7859
7893
  if (response?.cancelled && !this.cancelController.signal.aborted) {
7860
7894
  this.observedCancelReason = response.cancelReason ?? null;
7861
- this.cancelController.abort(/* @__PURE__ */ new Error(`Task cancelled by imposer${this.observedCancelReason ? `: ${this.observedCancelReason}` : ""}`));
7895
+ this.cancelController.abort(/* @__PURE__ */ new Error(`Task cancelled by proposer${this.observedCancelReason ? `: ${this.observedCancelReason}` : ""}`));
7862
7896
  if (this.heartbeatTimer) {
7863
7897
  clearInterval(this.heartbeatTimer);
7864
7898
  this.heartbeatTimer = null;
@@ -7935,7 +7969,7 @@ var AgentRuntime = class {
7935
7969
  outputCid: null,
7936
7970
  error: {
7937
7971
  code: "task_cancelled",
7938
- message: reporter.cancelReason ?? "Task cancelled by imposer while executor was running.",
7972
+ message: reporter.cancelReason ?? "Task cancelled by proposer while executor was running.",
7939
7973
  retryable: false
7940
7974
  }
7941
7975
  };
@@ -10458,7 +10492,7 @@ var MoltNetError = class extends Error {
10458
10492
  /**
10459
10493
  * Populated when the server returned a `VALIDATION_FAILED` problem
10460
10494
  * (status 400) with field-level errors. Empty / undefined for every
10461
- * other problem kind. Imposer scripts surface these to operators so
10495
+ * other problem kind. Proposer scripts surface these to operators so
10462
10496
  * they don't have to re-run with curl to see what was rejected.
10463
10497
  */
10464
10498
  validationErrors;
@@ -17418,7 +17452,7 @@ async function executePiTask(claimedTask, reporter, opts) {
17418
17452
  durationMs: Date.now() - startTime,
17419
17453
  error: {
17420
17454
  code: "task_cancelled",
17421
- message: reporter.cancelReason ?? "Task cancelled by imposer while pi session was running.",
17455
+ message: reporter.cancelReason ?? "Task cancelled by proposer while pi session was running.",
17422
17456
  retryable: false
17423
17457
  }
17424
17458
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.10.5",
3
+ "version": "0.11.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,19 +33,19 @@
33
33
  "@opentelemetry/semantic-conventions": "^1.39.0",
34
34
  "pino": "^10.3.1",
35
35
  "pino-pretty": "^13.1.3",
36
- "@themoltnet/agent-runtime": "0.18.4",
37
- "@themoltnet/pi-extension": "0.19.5",
38
- "@themoltnet/sdk": "0.105.0"
36
+ "@themoltnet/pi-extension": "0.20.0",
37
+ "@themoltnet/agent-runtime": "0.19.0",
38
+ "@themoltnet/sdk": "0.106.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsx": "^4.7.0",
42
- "typescript": "^5.3.3",
42
+ "typescript": "~5.9.2",
43
43
  "vite": "^8.0.0",
44
44
  "vitest": "^3.0.0",
45
- "@moltnet/crypto-service": "0.1.0",
46
- "@moltnet/database": "0.1.0",
47
45
  "@moltnet/bootstrap": "0.1.0",
48
- "@moltnet/tasks": "0.1.0"
46
+ "@moltnet/tasks": "0.1.0",
47
+ "@moltnet/crypto-service": "0.1.0",
48
+ "@moltnet/database": "0.1.0"
49
49
  },
50
50
  "nx": {
51
51
  "tags": [