@themoltnet/agent-daemon 0.37.0 → 0.38.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.
package/README.md CHANGED
@@ -129,10 +129,10 @@ To force a non-repo Pi directory, set
129
129
 
130
130
  ### Observability
131
131
 
132
- | Var | Default | Purpose |
133
- | ----------------------- | ------- | --------------------------------------- |
134
- | `MOLTNET_OTEL_ENDPOINT` | unset | OTLP traces endpoint. Empty = disabled. |
135
- | `LOG_LEVEL` | `info` | Pino log level override. |
132
+ | Var | Default | Purpose |
133
+ | ----------------------- | ------- | --------------------------------------------------- |
134
+ | `MOLTNET_OTEL_ENDPOINT` | unset | OTLP traces and metrics endpoint. Empty = disabled. |
135
+ | `LOG_LEVEL` | `info` | Pino log level override. |
136
136
 
137
137
  ### Host command auto-approval
138
138
 
package/dist/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { defaultPiDaemonAdapter } from "./pi.js";
3
3
  import { assertRuntimeAdapterSupportsProfile } from "./runtime.js";
4
- import * as Format from "typebox/format";
5
4
  import { Type } from "typebox";
6
5
  import crypto from "crypto";
7
6
  import { Value } from "typebox/value";
@@ -15,8 +14,11 @@ import { AuthenticationError, MoltNetError, connect } from "@themoltnet/sdk";
15
14
  import { createHash, randomUUID } from "node:crypto";
16
15
  import { once } from "node:events";
17
16
  import { pino, transport } from "pino";
17
+ import { metrics } from "@opentelemetry/api";
18
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
18
19
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
19
20
  import { resourceFromAttributes } from "@opentelemetry/resources";
21
+ import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
20
22
  import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
21
23
  import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
22
24
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
@@ -26,19 +28,6 @@ import { mkdir, realpath, stat } from "node:fs/promises";
26
28
  import { pipeline } from "node:stream/promises";
27
29
  import { Writable } from "node:stream";
28
30
  import { createGzip } from "node:zlib";
29
- //#region ../../libs/tasks/src/formats.ts
30
- /**
31
- * Register TypeBox string formats used across Task / TaskOutput / task-type
32
- * schemas. Import this module for its side effect (the package index does so
33
- * automatically) before compiling or Check()ing any schema that references
34
- * `format: 'uuid'` or `format: 'date-time'`.
35
- *
36
- * Idempotent: registration is guarded by `Format.Has(...)`.
37
- */
38
- var UUID_RE$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
39
- if (!Format.Has("uuid")) Format.Set("uuid", (v) => UUID_RE$1.test(v));
40
- if (!Format.Has("date-time")) Format.Set("date-time", (v) => !Number.isNaN(Date.parse(v)));
41
- //#endregion
42
31
  //#region ../../libs/tasks/src/context.ts
43
32
  /**
44
33
  * How an executor delivers a context entry to its underlying LLM.
@@ -3781,7 +3770,7 @@ Type.Object({
3781
3770
  daemonState: Type.Union([DaemonState, Type.Null()])
3782
3771
  }, {
3783
3772
  $id: "TaskAttempt",
3784
- additionalProperties: false
3773
+ additionalProperties: true
3785
3774
  });
3786
3775
  Type.Object({
3787
3776
  taskId: Uuid,
@@ -4130,9 +4119,16 @@ function loadConfig() {
4130
4119
  profilePrerequisiteEnv: process.env,
4131
4120
  profilePrerequisitePath: process.env.PATH ?? "",
4132
4121
  piCodingAgentDir: process.env["PI_CODING_AGENT_DIR"] ?? "",
4133
- authMode: detectAuthMode(process.env)
4122
+ authMode: detectAuthMode(process.env),
4123
+ traceIdlePolling: readBoolean("MOLTNET_TRACE_IDLE_POLLING", process.env["MOLTNET_TRACE_IDLE_POLLING"])
4134
4124
  };
4135
4125
  }
4126
+ function readBoolean(name, value) {
4127
+ if (value === void 0 || value === "") return false;
4128
+ if (value === "true") return true;
4129
+ if (value === "false") return false;
4130
+ throw new Error(`${name} must be either true or false`);
4131
+ }
4136
4132
  function activatePiCodingAgentDir(path) {
4137
4133
  process.env["PI_CODING_AGENT_DIR"] = path;
4138
4134
  }
@@ -5142,8 +5138,8 @@ function validateTaskTypes(types) {
5142
5138
  * try { ... } finally { await shutdown(); }
5143
5139
  *
5144
5140
  * No-op when MOLTNET_OTEL_ENDPOINT is unset — `@opentelemetry/api` falls
5145
- * back to no-op tracers, so the runtime + pi extension still call into
5146
- * it but nothing is exported.
5141
+ * back to no-op tracers and meters, so the runtime + pi extension still
5142
+ * call into it but nothing is exported.
5147
5143
  */
5148
5144
  async function initWorkerOtel(options) {
5149
5145
  const endpoint = options.endpoint;
@@ -5161,21 +5157,38 @@ async function initWorkerOtel(options) {
5161
5157
  return { Authorization: `Bearer ${await agent.getToken()}` };
5162
5158
  };
5163
5159
  }
5160
+ const exporter = new OTLPTraceExporter({
5161
+ url: `${endpoint.replace(/\/$/, "")}/v1/traces`,
5162
+ ...headersFactory && { headers: headersFactory }
5163
+ });
5164
+ const metricExporter = new OTLPMetricExporter({
5165
+ url: `${endpoint.replace(/\/$/, "")}/v1/metrics`,
5166
+ ...headersFactory && { headers: headersFactory }
5167
+ });
5164
5168
  const provider = new NodeTracerProvider({
5165
5169
  resource,
5166
- spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter({
5167
- url: `${endpoint.replace(/\/$/, "")}/v1/traces`,
5168
- ...headersFactory && { headers: headersFactory }
5169
- }))]
5170
+ spanProcessors: [new BatchSpanProcessor(exporter)]
5171
+ });
5172
+ const meterProvider = new MeterProvider({
5173
+ resource,
5174
+ readers: [new PeriodicExportingMetricReader({
5175
+ exporter: metricExporter,
5176
+ exportIntervalMillis: 6e4
5177
+ })]
5170
5178
  });
5171
5179
  provider.register();
5180
+ metrics.setGlobalMeterProvider(meterProvider);
5172
5181
  return async () => {
5173
- await provider.forceFlush().catch((err) => {
5174
- process.stderr.write(`[otel-bootstrap] forceFlush failed: ${err instanceof Error ? err.message : String(err)}\n`);
5175
- });
5176
- await provider.shutdown().catch((err) => {
5177
- process.stderr.write(`[otel-bootstrap] shutdown failed: ${err instanceof Error ? err.message : String(err)}\n`);
5178
- });
5182
+ await Promise.all([provider.forceFlush().catch((err) => {
5183
+ process.stderr.write(`[otel-bootstrap] trace forceFlush failed: ${err instanceof Error ? err.message : String(err)}\n`);
5184
+ }), meterProvider.forceFlush().catch((err) => {
5185
+ process.stderr.write(`[otel-bootstrap] metric forceFlush failed: ${err instanceof Error ? err.message : String(err)}\n`);
5186
+ })]);
5187
+ await Promise.all([provider.shutdown().catch((err) => {
5188
+ process.stderr.write(`[otel-bootstrap] trace shutdown failed: ${err instanceof Error ? err.message : String(err)}\n`);
5189
+ }), meterProvider.shutdown().catch((err) => {
5190
+ process.stderr.write(`[otel-bootstrap] metric shutdown failed: ${err instanceof Error ? err.message : String(err)}\n`);
5191
+ })]);
5179
5192
  };
5180
5193
  }
5181
5194
  //#endregion
@@ -5994,6 +6007,7 @@ async function runPolling(opts) {
5994
6007
  resourceAttributes: {
5995
6008
  "moltnet.team.id": teamId,
5996
6009
  "moltnet.agent.name": baseCommon.agent,
6010
+ "moltnet.auth.mode": cfg.authMode,
5997
6011
  "moltnet.runtime_profile.count": String(profiles.length),
5998
6012
  "moltnet.runtime_profile.ids": profiles.map((p) => p.id).join(",")
5999
6013
  }
@@ -6135,6 +6149,7 @@ async function runPolling(opts) {
6135
6149
  waitForFirstTaskMs: waitForFirstTaskSec * 1e3,
6136
6150
  waitAfterTaskMs: waitAfterTaskSec * 1e3,
6137
6151
  debug: baseCommon.debug,
6152
+ traceIdlePolling: cfg.traceIdlePolling,
6138
6153
  logger: rootLogger,
6139
6154
  executorFingerprints: Object.fromEntries(profiles.map((profile) => [profile.id, requireRuntime(runtimes, profile.id).preparedRuntime.attestor.fingerprint])),
6140
6155
  slotRegistry,
@@ -6522,6 +6537,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6522
6537
  resourceAttributes: {
6523
6538
  "moltnet.task.id": taskId,
6524
6539
  "moltnet.agent.name": opts.agent,
6540
+ "moltnet.auth.mode": cfg.authMode,
6525
6541
  "moltnet.llm.provider": profile.provider,
6526
6542
  "moltnet.llm.model": profile.model,
6527
6543
  ...profile.thinkingLevel ? { "moltnet.llm.thinking_level": profile.thinkingLevel } : {},
package/dist/pi.d.ts CHANGED
@@ -2,5 +2,6 @@ import { PiRuntimeDefinition } from '@themoltnet/pi-runtime';
2
2
  import { DaemonRuntimeAdapter } from './runtime.js';
3
3
  export declare const PI_KERNEL_TOOL_NAMES: readonly ["read", "write", "edit", "bash", "ls", "find", "grep", "subagent", "moltnet_pack_get", "moltnet_pack_create", "moltnet_pack_provenance", "moltnet_pack_render", "moltnet_rendered_pack_list", "moltnet_rendered_pack_get", "moltnet_diary_tags", "moltnet_list_entries", "moltnet_get_entry", "moltnet_search_entries", "moltnet_create_entry", "moltnet_get_task", "moltnet_list_task_attempts", "moltnet_list_task_messages", "moltnet_upload_task_artifact", "moltnet_list_task_artifacts", "moltnet_download_task_artifact", "moltnet_review_session_errors", "moltnet_host_exec"];
4
4
  export declare function createPiDaemonAdapter(runtime: PiRuntimeDefinition): DaemonRuntimeAdapter;
5
+ export declare const defaultPiRuntimeDefinition: PiRuntimeDefinition;
5
6
  export declare const defaultPiDaemonAdapter: DaemonRuntimeAdapter;
6
7
  //# sourceMappingURL=pi.d.ts.map
package/dist/pi.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,oBAAoB,EAAyB,MAAM,cAAc,CAAC;AAEhF,eAAO,MAAM,oBAAoB,kkBAIvB,CAAC;AAEX,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAC3B,oBAAoB,CAiEtB;AAED,eAAO,MAAM,sBAAsB,sBASlC,CAAC"}
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,oBAAoB,EAAyB,MAAM,cAAc,CAAC;AAEhF,eAAO,MAAM,oBAAoB,kkBAIvB,CAAC;AAEX,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAC3B,oBAAoB,CAiEtB;AAED,eAAO,MAAM,0BAA0B,qBAQrC,CAAC;AAEH,eAAO,MAAM,sBAAsB,sBAElC,CAAC"}
package/dist/pi.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { GONDOLIN_TOOL_NAMES, MOLTNET_TOOL_NAMES, buildPiExecutorManifest, createPiTaskExecutor, defineGondolinTemplate, definePiRuntime } from "@themoltnet/pi-runtime";
2
+ import { GONDOLIN_BASE_EXECUTABLES, GONDOLIN_TOOL_NAMES, MOLTNET_TOOL_NAMES, buildPiExecutorManifest, createPiTaskExecutor, defineGondolinTemplate, definePiRuntime } from "@themoltnet/pi-runtime";
3
3
  import { createExecutorAttestor } from "@themoltnet/sdk";
4
4
  //#region src/pi.ts
5
5
  var PI_KERNEL_TOOL_NAMES = [
@@ -58,13 +58,15 @@ function createPiDaemonAdapter(runtime) {
58
58
  }
59
59
  };
60
60
  }
61
- var defaultPiDaemonAdapter = createPiDaemonAdapter(definePiRuntime({
61
+ var defaultPiRuntimeDefinition = definePiRuntime({
62
62
  id: "moltnet-default-pi",
63
63
  version: "1",
64
64
  vm: defineGondolinTemplate({
65
65
  id: "moltnet-default-gondolin",
66
- version: "1"
66
+ version: "1",
67
+ executables: GONDOLIN_BASE_EXECUTABLES
67
68
  })
68
- }));
69
+ });
70
+ var defaultPiDaemonAdapter = createPiDaemonAdapter(defaultPiRuntimeDefinition);
69
71
  //#endregion
70
- export { PI_KERNEL_TOOL_NAMES, createPiDaemonAdapter, defaultPiDaemonAdapter };
72
+ export { PI_KERNEL_TOOL_NAMES, createPiDaemonAdapter, defaultPiDaemonAdapter, defaultPiRuntimeDefinition };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "Universal MoltNet agent daemon host with a built-in Pi/Gondolin runtime and support for trusted operator-owned runtime modules. CLI: moltnet-agent.",
@@ -36,8 +36,12 @@
36
36
  },
37
37
  "files": [
38
38
  "dist/*.js",
39
- "dist/*.d.ts",
40
- "dist/*.d.ts.map"
39
+ "dist/cli.d.ts",
40
+ "dist/cli.d.ts.map",
41
+ "dist/pi.d.ts",
42
+ "dist/pi.d.ts.map",
43
+ "dist/runtime.d.ts",
44
+ "dist/runtime.d.ts.map"
41
45
  ],
42
46
  "engines": {
43
47
  "node": ">=22"
@@ -47,6 +51,7 @@
47
51
  "@earendil-works/pi-ai": "0.79.4",
48
52
  "@earendil-works/pi-coding-agent": "0.79.4",
49
53
  "@opentelemetry/api": "^1.9.0",
54
+ "@opentelemetry/exporter-metrics-otlp-proto": "^0.212.0",
50
55
  "@opentelemetry/exporter-trace-otlp-proto": "^0.212.0",
51
56
  "@opentelemetry/instrumentation": "^0.212.0",
52
57
  "@opentelemetry/instrumentation-dns": "^0.55.0",
@@ -56,15 +61,16 @@
56
61
  "@opentelemetry/instrumentation-pino": "^0.58.0",
57
62
  "@opentelemetry/instrumentation-undici": "^0.22.0",
58
63
  "@opentelemetry/resources": "^2.5.1",
64
+ "@opentelemetry/sdk-metrics": "^2.5.1",
59
65
  "@opentelemetry/sdk-trace-base": "^2.5.1",
60
66
  "@opentelemetry/sdk-trace-node": "^2.5.1",
61
67
  "@opentelemetry/semantic-conventions": "^1.39.0",
62
68
  "pino": "^10.3.1",
63
69
  "pino-pretty": "^13.1.3",
64
70
  "typebox": "^1.2.8",
65
- "@themoltnet/agent-runtime": "0.40.1",
66
- "@themoltnet/sdk": "0.129.0",
67
- "@themoltnet/pi-runtime": "0.6.1"
71
+ "@themoltnet/agent-runtime": "0.41.0",
72
+ "@themoltnet/pi-runtime": "0.7.0",
73
+ "@themoltnet/sdk": "0.129.0"
68
74
  },
69
75
  "devDependencies": {
70
76
  "tsx": "^4.7.0",
@@ -74,8 +80,8 @@
74
80
  "vitest": "^3.0.0",
75
81
  "@moltnet/bootstrap": "0.1.0",
76
82
  "@moltnet/crypto-service": "0.1.0",
77
- "@moltnet/observability": "0.1.0",
78
- "@moltnet/tasks": "0.1.0"
83
+ "@moltnet/tasks": "0.1.0",
84
+ "@moltnet/observability": "0.1.0"
79
85
  },
80
86
  "nx": {
81
87
  "projectType": "application",
package/dist/config.d.ts DELETED
@@ -1,22 +0,0 @@
1
- import { DaemonAuthMode } from './lib/agent-context.js';
2
- export interface DaemonConfig {
3
- /** OTLP endpoint for trace export. Empty = OTel bootstrap is a no-op. */
4
- otelEndpoint: string;
5
- /** Pino log level override; empty = per-mode default (info, or debug with --debug). */
6
- logLevel: string;
7
- /** Process environment visible to profile prerequisite checks. */
8
- profilePrerequisiteEnv: NodeJS.ProcessEnv;
9
- /** PATH used when resolving profile requiredTools. */
10
- profilePrerequisitePath: string;
11
- /** Optional Pi agent dir override. Empty = daemon defaults to repo-local .pi. */
12
- piCodingAgentDir: string;
13
- /**
14
- * Which credential `connect()` will use: `agent-key` when `MOLTNET_AGENT_KEY`
15
- * is set, otherwise the default `oauth2` client-credentials flow. The secret
16
- * itself is never surfaced here.
17
- */
18
- authMode: DaemonAuthMode;
19
- }
20
- export declare function loadConfig(): DaemonConfig;
21
- export declare function activatePiCodingAgentDir(path: string): void;
22
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,sBAAsB,EAAE,MAAM,CAAC,UAAU,CAAC;IAC1C,sDAAsD;IACtD,uBAAuB,EAAE,MAAM,CAAC;IAChC,iFAAiF;IACjF,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,wBAAgB,UAAU,IAAI,YAAY,CASzC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3D"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=instrumentation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":""}
package/dist/main.d.ts DELETED
@@ -1 +0,0 @@
1
- //# sourceMappingURL=main.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC"}
@@ -1,11 +0,0 @@
1
- import { DaemonRuntimeAdapter } from './runtime.js';
2
- export interface RuntimeModuleSelection {
3
- readonly argv: string[];
4
- readonly specifier?: string;
5
- }
6
- export declare function extractRuntimeModule(argv: readonly string[]): RuntimeModuleSelection;
7
- export declare function resolveRuntimeModuleUrl(specifier: string, cwd?: string): string;
8
- export declare function loadDaemonRuntimeAdapter(specifier: string, options?: {
9
- cwd?: string;
10
- }): Promise<DaemonRuntimeAdapter>;
11
- //# sourceMappingURL=runtime-loader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-loader.d.ts","sourceRoot":"","sources":["../src/runtime-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,sBAAsB,CAyCxB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,GAAG,SAAgB,GAClB,MAAM,CAcR;AAED,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA2B/B"}