@themoltnet/agent-daemon 0.11.0 → 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 +5 -0
  2. package/dist/main.js +171 -103
  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.
package/dist/main.js CHANGED
@@ -4190,6 +4190,59 @@ var CuratePackOutput = Type$2.Object({
4190
4190
  additionalProperties: false
4191
4191
  });
4192
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
4193
4246
  //#region ../../libs/tasks/src/task-types/fulfill-brief.ts
4194
4247
  /**
4195
4248
  * `fulfill_brief` — produce a signed change against a coding brief.
@@ -4748,6 +4801,16 @@ function requireVerificationWhenCriteriaPresent(output, input) {
4748
4801
  * / claiming a task.
4749
4802
  */
4750
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
+ },
4751
4814
  [FULFILL_BRIEF_TYPE]: {
4752
4815
  name: FULFILL_BRIEF_TYPE,
4753
4816
  inputSchema: FulfillBriefInput,
@@ -6802,6 +6865,97 @@ function buildCuratePackUserPrompt(input, ctx) {
6802
6865
  ]);
6803
6866
  }
6804
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
6805
6959
  //#region ../../libs/agent-runtime/src/prompts/fulfill-brief.ts
6806
6960
  /**
6807
6961
  * Build the first user-message prompt for a `fulfill_brief` task.
@@ -6851,7 +7005,11 @@ function buildFulfillBriefUserPrompt(input, ctx) {
6851
7005
  "5. For every commit, create a signed diary entry first via",
6852
7006
  " `moltnet_create_entry` and embed its id in the commit trailer",
6853
7007
  " `MoltNet-Diary: <id>` (per the runtime instructor).",
6854
- "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."
6855
7013
  ].join("\n");
6856
7014
  return assembleTaskPrompt("fulfill_brief", [
6857
7015
  {
@@ -7551,6 +7709,12 @@ function buildRunEvalUserPrompt(input, ctx) {
7551
7709
  */
7552
7710
  function buildTaskUserPrompt(task, ctx) {
7553
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 });
7554
7718
  case FULFILL_BRIEF_TYPE:
7555
7719
  if (!Check(FulfillBriefInput, task.input)) {
7556
7720
  const errors = [...Errors(FulfillBriefInput, task.input)];
@@ -9115,84 +9279,6 @@ var searchDiary = (options) => (options?.client ?? client).post({
9115
9279
  }
9116
9280
  });
9117
9281
  /**
9118
- * Get a digest of recent diary entries.
9119
- */
9120
- var reflectDiary = (options) => (options.client ?? client).get({
9121
- security: [
9122
- {
9123
- scheme: "bearer",
9124
- type: "http"
9125
- },
9126
- {
9127
- name: "X-Moltnet-Session-Token",
9128
- type: "apiKey"
9129
- },
9130
- {
9131
- in: "cookie",
9132
- name: "ory_kratos_session",
9133
- type: "apiKey"
9134
- }
9135
- ],
9136
- url: "/diaries/reflect",
9137
- ...options
9138
- });
9139
- /**
9140
- * [DEPRECATED] Server-side consolidation is obsolete. Compose consolidation suggestions client-side using diary search + clustering. Cluster semantically similar entries and return consolidation suggestions.
9141
- *
9142
- * @deprecated
9143
- */
9144
- var consolidateDiary = (options) => (options.client ?? client).post({
9145
- security: [
9146
- {
9147
- scheme: "bearer",
9148
- type: "http"
9149
- },
9150
- {
9151
- name: "X-Moltnet-Session-Token",
9152
- type: "apiKey"
9153
- },
9154
- {
9155
- in: "cookie",
9156
- name: "ory_kratos_session",
9157
- type: "apiKey"
9158
- }
9159
- ],
9160
- url: "/diaries/{id}/consolidate",
9161
- ...options,
9162
- headers: {
9163
- "Content-Type": "application/json",
9164
- ...options.headers
9165
- }
9166
- });
9167
- /**
9168
- * [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.
9169
- *
9170
- * @deprecated
9171
- */
9172
- var compileDiary = (options) => (options.client ?? client).post({
9173
- security: [
9174
- {
9175
- scheme: "bearer",
9176
- type: "http"
9177
- },
9178
- {
9179
- name: "X-Moltnet-Session-Token",
9180
- type: "apiKey"
9181
- },
9182
- {
9183
- in: "cookie",
9184
- name: "ory_kratos_session",
9185
- type: "apiKey"
9186
- }
9187
- ],
9188
- url: "/diaries/{id}/compile",
9189
- ...options,
9190
- headers: {
9191
- "Content-Type": "application/json",
9192
- ...options.headers
9193
- }
9194
- });
9195
- /**
9196
9282
  * Export the provenance graph for a persisted context pack by ID.
9197
9283
  */
9198
9284
  var getContextPackProvenanceById = (options) => (options.client ?? client).get({
@@ -10668,22 +10754,6 @@ function createDiariesNamespace(context) {
10668
10754
  path: { id }
10669
10755
  }));
10670
10756
  },
10671
- async consolidate(id, body) {
10672
- return unwrapResult(await consolidateDiary({
10673
- client,
10674
- auth,
10675
- path: { id },
10676
- body
10677
- }));
10678
- },
10679
- async compile(id, body) {
10680
- return unwrapResult(await compileDiary({
10681
- client,
10682
- auth,
10683
- path: { id },
10684
- body
10685
- }));
10686
- },
10687
10757
  async tags(diaryId, query) {
10688
10758
  return unwrapResult(await listDiaryTags({
10689
10759
  client,
@@ -11755,13 +11825,6 @@ function createEntriesNamespace(context) {
11755
11825
  body
11756
11826
  }));
11757
11827
  },
11758
- async reflect(query) {
11759
- return unwrapResult(await reflectDiary({
11760
- client,
11761
- auth,
11762
- query
11763
- }));
11764
- },
11765
11828
  async verify(entryId) {
11766
11829
  return unwrapResult(await verifyDiaryEntryById({
11767
11830
  client,
@@ -15203,7 +15266,7 @@ function createMoltNetTools(config) {
15203
15266
  defineTool({
15204
15267
  name: "moltnet_host_exec",
15205
15268
  label: "Run command on host (escape hatch — requires user approval)",
15206
- 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.",
15207
15270
  parameters: Type.Object({
15208
15271
  executable: Type.String({ description: "Executable to run (git | gh | moltnet)" }),
15209
15272
  args: Type.Array(Type.String(), { description: "Arguments to pass to the executable" }),
@@ -16277,6 +16340,11 @@ function buildRuntimeInstructor(ctx) {
16277
16340
  "",
16278
16341
  "- `git push` uses the gitconfig-configured credential helper and is not",
16279
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.",
16280
16348
  "",
16281
16349
  "## Diary discipline",
16282
16350
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.11.0",
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,8 +33,8 @@
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.20.0",
37
- "@themoltnet/agent-runtime": "0.19.0",
36
+ "@themoltnet/agent-runtime": "0.19.1",
37
+ "@themoltnet/pi-extension": "0.20.1",
38
38
  "@themoltnet/sdk": "0.106.0"
39
39
  },
40
40
  "devDependencies": {
@@ -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/tasks": "0.1.0",
47
46
  "@moltnet/crypto-service": "0.1.0",
48
- "@moltnet/database": "0.1.0"
47
+ "@moltnet/database": "0.1.0",
48
+ "@moltnet/tasks": "0.1.0"
49
49
  },
50
50
  "nx": {
51
51
  "tags": [