@themoltnet/agent-daemon 0.17.0 → 0.18.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 +19 -8
- package/dist/main.js +59 -8
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -50,8 +50,17 @@ The agent's `moltnet.json` and gitconfig live next to each other in
|
|
|
50
50
|
|
|
51
51
|
### Pi provider auth
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
The daemon resolves Pi config from the repository-local `.pi` directory by
|
|
54
|
+
default. On startup, if `PI_CODING_AGENT_DIR` is not already set, the daemon
|
|
55
|
+
sets it to `<repo-root>/.pi` before creating Pi sessions. This keeps daemon
|
|
56
|
+
runs deterministic and avoids inheriting user-level `~/.pi/agent` state.
|
|
57
|
+
|
|
58
|
+
Repo-local `.pi/settings.json` and `.pi/models.json` are intended to be
|
|
59
|
+
committed. `models.json` should reference provider keys by environment-variable
|
|
60
|
+
name, for example `"apiKey": "OLLAMA_API_KEY"`, not contain secret values.
|
|
61
|
+
Repo-local `.pi/auth.json` may exist for local subscription auth, but is
|
|
62
|
+
gitignored. Without `.pi/auth.json`, Pi falls back to environment-variable
|
|
63
|
+
provider keys:
|
|
55
64
|
|
|
56
65
|
```bash
|
|
57
66
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
@@ -59,7 +68,8 @@ export ANTHROPIC_API_KEY=sk-ant-...
|
|
|
59
68
|
# https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/env-api-keys.ts
|
|
60
69
|
```
|
|
61
70
|
|
|
62
|
-
To
|
|
71
|
+
To force a non-repo Pi directory, set
|
|
72
|
+
`PI_CODING_AGENT_DIR=/abs/path/to/.pi-or-agent-dir` before starting the daemon.
|
|
63
73
|
|
|
64
74
|
### Observability
|
|
65
75
|
|
|
@@ -126,11 +136,12 @@ registered task type; unknown task-type names remain invalid.
|
|
|
126
136
|
### Prerequisites
|
|
127
137
|
|
|
128
138
|
- Docker running.
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
- Pi config for the model provider you'll drive the daemon with. Local daemon
|
|
140
|
+
runs default `PI_CODING_AGENT_DIR` to repo-local `.pi`, so committed
|
|
141
|
+
`.pi/settings.json` and `.pi/models.json` must list the provider/model. For
|
|
142
|
+
subscription auth, put your local token blob in `.pi/auth.json`; it is
|
|
143
|
+
gitignored. For API-key auth, keep `.pi/auth.json` absent and export the
|
|
144
|
+
provider key referenced by `.pi/models.json`, for example `OLLAMA_API_KEY`.
|
|
134
145
|
- `ssh-keygen` on `PATH`.
|
|
135
146
|
- A `sandbox.json` at the repo root, or an explicit `--sandbox <path>` when
|
|
136
147
|
starting the daemon. The daemon searches up for this file and uses its
|
package/dist/main.js
CHANGED
|
@@ -31258,12 +31258,21 @@ if (!etc.sha512Sync) etc.sha512Sync = (...m) => {
|
|
|
31258
31258
|
*/
|
|
31259
31259
|
async function isContinuationClaimableByThisDaemon(task, slotRegistry) {
|
|
31260
31260
|
const cf = task.input?.continueFrom;
|
|
31261
|
-
if (!cf) return true;
|
|
31261
|
+
if (!cf) return { claimable: true };
|
|
31262
31262
|
const slot = await slotRegistry.findLatestProducerSlotByTaskAttempt(cf.taskId, cf.attemptN);
|
|
31263
|
-
if (!slot) return
|
|
31263
|
+
if (!slot) return {
|
|
31264
|
+
claimable: false,
|
|
31265
|
+
reason: "missing_producer_slot",
|
|
31266
|
+
continueFrom: cf
|
|
31267
|
+
};
|
|
31264
31268
|
const sessionDir = slot.session?.sessionDir;
|
|
31265
|
-
if (!sessionDir || !existsSync(sessionDir)) return
|
|
31266
|
-
|
|
31269
|
+
if (!sessionDir || !existsSync(sessionDir)) return {
|
|
31270
|
+
claimable: false,
|
|
31271
|
+
reason: "missing_session_dir",
|
|
31272
|
+
continueFrom: cf,
|
|
31273
|
+
sessionDir
|
|
31274
|
+
};
|
|
31275
|
+
return { claimable: true };
|
|
31267
31276
|
}
|
|
31268
31277
|
var DEFAULT_LIST_LIMIT = 10;
|
|
31269
31278
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
@@ -31351,7 +31360,19 @@ var PollingApiTaskSource = class {
|
|
|
31351
31360
|
if (seen.has(item.id)) continue;
|
|
31352
31361
|
if (this.opts.taskTypes && this.opts.taskTypes.length > 0 && !this.opts.taskTypes.includes(item.taskType)) continue;
|
|
31353
31362
|
if (this.opts.diaryIds && this.opts.diaryIds.length > 0 && (item.diaryId === null || !this.opts.diaryIds.includes(item.diaryId))) continue;
|
|
31354
|
-
if (this.opts.slotRegistry
|
|
31363
|
+
if (this.opts.slotRegistry) {
|
|
31364
|
+
const affinity = await isContinuationClaimableByThisDaemon(item, this.opts.slotRegistry);
|
|
31365
|
+
if (!affinity.claimable) {
|
|
31366
|
+
this.logger.debug({
|
|
31367
|
+
taskId: item.id,
|
|
31368
|
+
taskType: item.taskType,
|
|
31369
|
+
reason: affinity.reason,
|
|
31370
|
+
continueFrom: affinity.continueFrom,
|
|
31371
|
+
sessionDir: affinity.sessionDir
|
|
31372
|
+
}, "polling-api.continuation_skipped");
|
|
31373
|
+
continue;
|
|
31374
|
+
}
|
|
31375
|
+
}
|
|
31355
31376
|
if (this.opts.profileId) {
|
|
31356
31377
|
const allowed = item.allowedProfiles ?? [];
|
|
31357
31378
|
if (allowed.length > 0 && !allowed.some((p) => p.profileId === this.opts.profileId)) continue;
|
|
@@ -34785,9 +34806,13 @@ function loadConfig() {
|
|
|
34785
34806
|
otelEndpoint: process.env["MOLTNET_OTEL_ENDPOINT"] ?? "",
|
|
34786
34807
|
logLevel: process.env["LOG_LEVEL"] ?? "",
|
|
34787
34808
|
profilePrerequisiteEnv: process.env,
|
|
34788
|
-
profilePrerequisitePath: process.env.PATH ?? ""
|
|
34809
|
+
profilePrerequisitePath: process.env.PATH ?? "",
|
|
34810
|
+
piCodingAgentDir: process.env["PI_CODING_AGENT_DIR"] ?? ""
|
|
34789
34811
|
};
|
|
34790
34812
|
}
|
|
34813
|
+
function activatePiCodingAgentDir(path) {
|
|
34814
|
+
process.env["PI_CODING_AGENT_DIR"] = path;
|
|
34815
|
+
}
|
|
34791
34816
|
//#endregion
|
|
34792
34817
|
//#region src/lib/agent-context.ts
|
|
34793
34818
|
/**
|
|
@@ -35052,6 +35077,7 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
|
|
|
35052
35077
|
return {
|
|
35053
35078
|
...basePlan,
|
|
35054
35079
|
workspaceMode: "dedicated_worktree",
|
|
35080
|
+
workspaceId: resolution.producerSlot.workspace?.workspaceId ?? null,
|
|
35055
35081
|
worktreeBranch: resolution.producerSlot.workspace?.worktreeBranch ?? null,
|
|
35056
35082
|
sessionPersistence: {
|
|
35057
35083
|
sessionDir: `${stateDirs.piSessionsDir}/continue-${claimedTask.task.id}-attempt-${claimedTask.attemptN}`,
|
|
@@ -35374,6 +35400,23 @@ async function initWorkerOtel(options) {
|
|
|
35374
35400
|
};
|
|
35375
35401
|
}
|
|
35376
35402
|
//#endregion
|
|
35403
|
+
//#region src/lib/pi-agent-dir.ts
|
|
35404
|
+
function ensurePiAgentDir(repoRoot, explicitPath) {
|
|
35405
|
+
if (explicitPath) {
|
|
35406
|
+
mkdirSync(explicitPath, { recursive: true });
|
|
35407
|
+
return {
|
|
35408
|
+
path: explicitPath,
|
|
35409
|
+
source: "env"
|
|
35410
|
+
};
|
|
35411
|
+
}
|
|
35412
|
+
const path = join(repoRoot, ".pi");
|
|
35413
|
+
mkdirSync(path, { recursive: true });
|
|
35414
|
+
return {
|
|
35415
|
+
path,
|
|
35416
|
+
source: "repo"
|
|
35417
|
+
};
|
|
35418
|
+
}
|
|
35419
|
+
//#endregion
|
|
35377
35420
|
//#region src/lib/runtime-profile.ts
|
|
35378
35421
|
var RuntimeProfilePrerequisiteError = class extends Error {
|
|
35379
35422
|
constructor(profileName, missingEnv, missingTools) {
|
|
@@ -35614,6 +35657,8 @@ async function runPolling(opts) {
|
|
|
35614
35657
|
rootDir: profile.mountPath,
|
|
35615
35658
|
path: profile.source
|
|
35616
35659
|
} : resolveSandbox(process.cwd(), values.sandbox);
|
|
35660
|
+
const piAgentDir = ensurePiAgentDir(sandbox.rootDir, cfg.piCodingAgentDir);
|
|
35661
|
+
activatePiCodingAgentDir(piAgentDir.path);
|
|
35617
35662
|
const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
|
|
35618
35663
|
const slotRegistry = new DaemonSlotRegistry(resolveDaemonStateStorageConfig(stateDirs.registryDbPath, cfg.agentDaemonStateDatabaseUrl));
|
|
35619
35664
|
const slotIdentity = {
|
|
@@ -35691,7 +35736,9 @@ async function runPolling(opts) {
|
|
|
35691
35736
|
profileId: profile.id,
|
|
35692
35737
|
profileSessionTtlSec: profile.sessionTtlSec,
|
|
35693
35738
|
profileWorkspaceTtlSec: profile.workspaceTtlSec
|
|
35694
|
-
} : {}
|
|
35739
|
+
} : {},
|
|
35740
|
+
piAgentDir: piAgentDir.path,
|
|
35741
|
+
piAgentDirSource: piAgentDir.source
|
|
35695
35742
|
}, "agent-daemon.starting");
|
|
35696
35743
|
const outputs = [];
|
|
35697
35744
|
try {
|
|
@@ -35967,6 +36014,8 @@ async function runOnce(argv) {
|
|
|
35967
36014
|
rootDir: profile.mountPath,
|
|
35968
36015
|
path: profile.source
|
|
35969
36016
|
} : resolveSandbox(process.cwd(), values.sandbox);
|
|
36017
|
+
const piAgentDir = ensurePiAgentDir(sandbox.rootDir, cfg.piCodingAgentDir);
|
|
36018
|
+
activatePiCodingAgentDir(piAgentDir.path);
|
|
35970
36019
|
const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
|
|
35971
36020
|
const slotRegistry = new DaemonSlotRegistry(resolveDaemonStateStorageConfig(stateDirs.registryDbPath, cfg.agentDaemonStateDatabaseUrl));
|
|
35972
36021
|
const slotIdentity = {
|
|
@@ -36017,7 +36066,9 @@ async function runOnce(argv) {
|
|
|
36017
36066
|
profileId: profile.id,
|
|
36018
36067
|
profileSessionTtlSec: profile.sessionTtlSec,
|
|
36019
36068
|
profileWorkspaceTtlSec: profile.workspaceTtlSec
|
|
36020
|
-
} : {}
|
|
36069
|
+
} : {},
|
|
36070
|
+
piAgentDir: piAgentDir.path,
|
|
36071
|
+
piAgentDirSource: piAgentDir.source
|
|
36021
36072
|
}, "agent-daemon.starting");
|
|
36022
36073
|
let runtime = null;
|
|
36023
36074
|
let activeAttemptN = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/agent-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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.",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"pino": "^10.3.1",
|
|
47
47
|
"pino-pretty": "^13.1.3",
|
|
48
48
|
"@themoltnet/agent-daemon-state": "0.2.0",
|
|
49
|
-
"@themoltnet/
|
|
50
|
-
"@themoltnet/
|
|
51
|
-
"@themoltnet/
|
|
49
|
+
"@themoltnet/agent-runtime": "0.25.0",
|
|
50
|
+
"@themoltnet/pi-extension": "0.24.0",
|
|
51
|
+
"@themoltnet/sdk": "0.108.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"tsx": "^4.7.0",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"vitest": "^3.0.0",
|
|
58
58
|
"@moltnet/bootstrap": "0.1.0",
|
|
59
59
|
"@moltnet/crypto-service": "0.1.0",
|
|
60
|
-
"@moltnet/
|
|
61
|
-
"@moltnet/
|
|
60
|
+
"@moltnet/tasks": "0.1.0",
|
|
61
|
+
"@moltnet/observability": "0.1.0"
|
|
62
62
|
},
|
|
63
63
|
"nx": {
|
|
64
64
|
"tags": [
|