@themoltnet/pi-runtime 0.3.0 → 0.5.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/dist/index.d.ts +57 -20
- package/dist/index.js +514 -526
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
4
|
-
import { readFile, realpath, stat } from "node:fs/promises";
|
|
4
|
+
import { mkdir, readFile, realpath, stat } from "node:fs/promises";
|
|
5
5
|
import path, { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { pipeline } from "node:stream/promises";
|
|
7
|
-
import { Type
|
|
8
|
-
import { DEFAULT_MAX_BYTES, DefaultResourceLoader, SessionManager, createAgentSession, createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createSyntheticSourceInfo, createWriteToolDefinition, defineTool, formatSize, parseFrontmatter, truncateHead, truncateLine } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
8
|
+
import { AuthStorage, DEFAULT_MAX_BYTES, DefaultResourceLoader, ModelRegistry, SessionManager, createAgentSession, createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createSyntheticSourceInfo, createWriteToolDefinition, defineTool, formatSize, parseFrontmatter, truncateHead, truncateLine } from "@earendil-works/pi-coding-agent";
|
|
9
9
|
import { SpanStatusCode, context, metrics, trace } from "@opentelemetry/api";
|
|
10
|
-
import { homedir } from "node:os";
|
|
11
10
|
import crypto, { createHash } from "crypto";
|
|
12
11
|
import { createHash as createHash$1 } from "node:crypto";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
import { Readable } from "node:stream";
|
|
15
15
|
import { MemoryProvider, RealFSProvider, ShadowProvider, VM, VmCheckpoint, createHttpHooks, createShadowPathPredicate, ensureImageSelector, isWriteFlag, loadGuestAssets } from "@earendil-works/gondolin";
|
|
@@ -43,6 +43,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
43
43
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp$1({}, "__esModule", { value: true }), mod);
|
|
44
44
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
45
45
|
//#endregion
|
|
46
|
+
//#region src/path-containment.ts
|
|
47
|
+
/**
|
|
48
|
+
* Check containment for already-resolved lexical or real paths.
|
|
49
|
+
*
|
|
50
|
+
* Callers that accept untrusted paths must resolve/realpath at their I/O
|
|
51
|
+
* boundary first; keeping the platform-specific relative-path rule here avoids
|
|
52
|
+
* subtly different `..` and absolute-path handling across runtime cleanup,
|
|
53
|
+
* session sync, and artifact staging.
|
|
54
|
+
*/
|
|
55
|
+
function isResolvedPathInsideRoot(path, root) {
|
|
56
|
+
const rel = relative(root, path);
|
|
57
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
46
60
|
//#region src/moltnet/render-phase6.ts
|
|
47
61
|
function slugToTitle(value) {
|
|
48
62
|
return value.split(/[:/_-]+/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -255,11 +269,32 @@ async function openWorkspaceArtifactInput(config, cwd, filePath) {
|
|
|
255
269
|
}
|
|
256
270
|
async function resolveWorkspaceOutputPath(cwd, filePath) {
|
|
257
271
|
const resolved = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(cwd, filePath);
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
if (
|
|
272
|
+
const workspaceRoot = path.resolve(cwd);
|
|
273
|
+
const lexicalRel = path.relative(workspaceRoot, resolved);
|
|
274
|
+
if (lexicalRel === "" || lexicalRel.startsWith("..") || path.isAbsolute(lexicalRel)) throw new Error(`task artifact output path escapes workspace: ${filePath}`);
|
|
275
|
+
const realCwd = await realpath(cwd);
|
|
276
|
+
const parent = path.dirname(resolved);
|
|
277
|
+
assertPathInsideWorkspace(realCwd, await findExistingAncestor(parent), filePath);
|
|
278
|
+
await mkdir(parent, { recursive: true });
|
|
279
|
+
assertPathInsideWorkspace(realCwd, await realpath(parent), filePath);
|
|
261
280
|
return resolved;
|
|
262
281
|
}
|
|
282
|
+
async function findExistingAncestor(candidate) {
|
|
283
|
+
let current = candidate;
|
|
284
|
+
for (;;) {
|
|
285
|
+
try {
|
|
286
|
+
return await realpath(current);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
if (!err || typeof err !== "object" || !("code" in err) || err.code !== "ENOENT") throw err;
|
|
289
|
+
}
|
|
290
|
+
const parent = path.dirname(current);
|
|
291
|
+
if (parent === current) throw new Error(`task artifact output has no existing ancestor: ${candidate}`);
|
|
292
|
+
current = parent;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function assertPathInsideWorkspace(realCwd, realPath, displayPath) {
|
|
296
|
+
if (!isResolvedPathInsideRoot(realPath, realCwd)) throw new Error(`task artifact output path escapes workspace: ${displayPath}`);
|
|
297
|
+
}
|
|
263
298
|
/**
|
|
264
299
|
* Expand the `taskFilter` shorthand on the diary list/search tools into
|
|
265
300
|
* the matching `task:*` provenance tags emitted by `moltnet_create_entry`
|
|
@@ -1258,6 +1293,7 @@ async function buildAgentSession(args) {
|
|
|
1258
1293
|
agentDir: args.piAuthDir,
|
|
1259
1294
|
cwd: args.cwdPath,
|
|
1260
1295
|
model: args.modelHandle,
|
|
1296
|
+
...args.modelRegistry ? { modelRegistry: args.modelRegistry } : {},
|
|
1261
1297
|
thinkingLevel: args.thinkingLevel ?? void 0,
|
|
1262
1298
|
tools: args.tools,
|
|
1263
1299
|
customTools: args.customTools,
|
|
@@ -9377,6 +9413,11 @@ var RuntimeModel = _Object_({
|
|
|
9377
9413
|
var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
9378
9414
|
version: 1,
|
|
9379
9415
|
fragments: {
|
|
9416
|
+
"artifact-planner-v1": {
|
|
9417
|
+
binding: "prompt_prefix",
|
|
9418
|
+
content: "# Bounded artifact planner\n\n- The typed task facts, embedded bounded manifest, exact bound artifact references, registered tools, and runtime capability section are the complete contract. Do not search diaries, inspect a mounted repository, enumerate unrelated tasks or artifacts, use shell commands, modify files, commit, branch, push, or contact GitHub.\n- Read only the exact artifact CIDs named by the task, and only when the embedded manifest does not provide enough evidence. Never paginate or discover artifacts speculatively.\n- Perform semantic classification and planning from supplied content and producer/consumer evidence. Do not substitute filename, directory, language, ecosystem, or repository-specific exclusion rules for evidence.\n- Return exactly the requested versioned structured plan through the registered submit-output tool. Do not emit a second prose or JSON representation.",
|
|
9419
|
+
slug: "artifact-planner-v1"
|
|
9420
|
+
},
|
|
9380
9421
|
"accountable-delivery-v1": {
|
|
9381
9422
|
binding: "prompt_prefix",
|
|
9382
9423
|
content: "# Accountable delivery\n\n- Pair every commit made during this task with a signed diary entry created by the `moltnet_create_entry` custom tool. Put the returned id in a `MoltNet-Diary: <id>` commit trailer.\n- Keep commit signing enabled; do not bypass the agent git configuration.\n- Push a branch and open or update a pull request only when the task asks for it. For GitHub mutations, use the credential-bound `GH_TOKEN` command form required by the runtime kernel.\n- Keep changes, commits, and any requested pull request coherent enough to review independently.",
|
|
@@ -9409,6 +9450,10 @@ var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
|
9409
9450
|
}
|
|
9410
9451
|
},
|
|
9411
9452
|
recipes: {
|
|
9453
|
+
"artifact-planner@v1": {
|
|
9454
|
+
description: "Minimal artifact-only context for bounded semantic classification and planning.",
|
|
9455
|
+
fragments: ["artifact-planner-v1"]
|
|
9456
|
+
},
|
|
9412
9457
|
"run-eval-direct@v1": {
|
|
9413
9458
|
description: "Minimal direct context for a short, isolated evaluation run.",
|
|
9414
9459
|
fragments: ["run-eval-direct-v1"]
|
|
@@ -10046,7 +10091,11 @@ var ProblemDetailsSchema = _Object_({
|
|
|
10046
10091
|
}),
|
|
10047
10092
|
code: ProblemCodeSchema,
|
|
10048
10093
|
detail: Optional(String$1()),
|
|
10049
|
-
instance: Optional(String$1())
|
|
10094
|
+
instance: Optional(String$1()),
|
|
10095
|
+
retryAfter: Optional(Integer({
|
|
10096
|
+
minimum: 0,
|
|
10097
|
+
description: "Non-negative delay in seconds before retrying, matching the Retry-After response header when present."
|
|
10098
|
+
}))
|
|
10050
10099
|
}, {
|
|
10051
10100
|
$id: "ProblemDetails",
|
|
10052
10101
|
additionalProperties: true
|
|
@@ -10892,7 +10941,7 @@ var VerificationResult = _Object_({
|
|
|
10892
10941
|
var VerificationRecord = _Object_({
|
|
10893
10942
|
inputCid: String$1({ minLength: 1 }),
|
|
10894
10943
|
results: _Array_(VerificationResult),
|
|
10895
|
-
passed: Boolean$1()
|
|
10944
|
+
passed: Boolean$1({ description: "True iff every verification result has status \"pass\" or \"skip\"; false when any result has status \"fail\"." })
|
|
10896
10945
|
}, {
|
|
10897
10946
|
$id: "VerificationRecord",
|
|
10898
10947
|
additionalProperties: false
|
|
@@ -14586,6 +14635,16 @@ function checkVerificationInputCid(value, runtime) {
|
|
|
14586
14635
|
}];
|
|
14587
14636
|
return [];
|
|
14588
14637
|
}
|
|
14638
|
+
function checkVerificationPassedConsistency(value) {
|
|
14639
|
+
const verification = value !== null && typeof value === "object" ? value.verification : void 0;
|
|
14640
|
+
if (verification === void 0 || !Array.isArray(verification.results) || typeof verification.passed !== "boolean") return [];
|
|
14641
|
+
const expectedPassed = verification.results.every((result) => result.status !== "fail");
|
|
14642
|
+
if (verification.passed !== expectedPassed) return [{
|
|
14643
|
+
field: "output/verification/passed",
|
|
14644
|
+
message: "must be true iff no verification result has status \"fail\""
|
|
14645
|
+
}];
|
|
14646
|
+
return [];
|
|
14647
|
+
}
|
|
14589
14648
|
function validateTaskResult(taskType, value, input, runtime, submission = false) {
|
|
14590
14649
|
const entry = getTaskTypeEntry(taskType);
|
|
14591
14650
|
if (!entry) return [{
|
|
@@ -14601,7 +14660,7 @@ function validateTaskResult(taskType, value, input, runtime, submission = false)
|
|
|
14601
14660
|
message: validationError
|
|
14602
14661
|
}];
|
|
14603
14662
|
}
|
|
14604
|
-
return checkVerificationInputCid(value, runtime);
|
|
14663
|
+
return [...checkVerificationInputCid(value, runtime), ...checkVerificationPassedConsistency(value)];
|
|
14605
14664
|
}
|
|
14606
14665
|
function validateTaskOutput(taskType, output, input, runtime) {
|
|
14607
14666
|
return validateTaskResult(taskType, output, input, runtime);
|
|
@@ -14991,6 +15050,10 @@ var TaskAttempt = _Object_({
|
|
|
14991
15050
|
taskId: Uuid,
|
|
14992
15051
|
attemptN: Number$1({ minimum: 1 }),
|
|
14993
15052
|
claimedByAgentId: Uuid,
|
|
15053
|
+
leaseId: Union([Uuid, Null()]),
|
|
15054
|
+
runtimeProfileId: Union([Uuid, Null()]),
|
|
15055
|
+
runtimeProfileRevision: Union([Integer({ minimum: 1 }), Null()]),
|
|
15056
|
+
policySnapshotHash: Union([String$1({ pattern: "^sha256:[0-9a-f]{64}$" }), Null()]),
|
|
14994
15057
|
runtimeId: Union([Uuid, Null()]),
|
|
14995
15058
|
claimedAt: IsoTimestamp,
|
|
14996
15059
|
startedAt: Union([IsoTimestamp, Null()]),
|
|
@@ -15147,69 +15210,6 @@ function assembleTaskPrompt(taskType, sections) {
|
|
|
15147
15210
|
};
|
|
15148
15211
|
}
|
|
15149
15212
|
//#endregion
|
|
15150
|
-
//#region ../agent-runtime/src/prompts/final-output.ts
|
|
15151
|
-
function buildFinalOutputBlock(opts) {
|
|
15152
|
-
const { taskType, outputSchemaName, shapeSketch, extraNotes } = opts;
|
|
15153
|
-
const submitTool = submitOutputToolName(taskType);
|
|
15154
|
-
const lines = [
|
|
15155
|
-
"## Final output (read this carefully)",
|
|
15156
|
-
"",
|
|
15157
|
-
`Your VERY LAST action in this conversation MUST report the structured`,
|
|
15158
|
-
`output matching \`${outputSchemaName}\`.`,
|
|
15159
|
-
"",
|
|
15160
|
-
`Call \`${submitTool}\` exactly once with the payload.`,
|
|
15161
|
-
`The runtime captures the validated arguments for attempt completion.`,
|
|
15162
|
-
`Do NOT emit the output as plain assistant text. Do NOT rely on a`,
|
|
15163
|
-
`JSON-in-message fallback. If you do not call \`${submitTool}\`, the`,
|
|
15164
|
-
`attempt is recorded as failing the promised submit-output criterion`,
|
|
15165
|
-
`even if the underlying work succeeded.`,
|
|
15166
|
-
"",
|
|
15167
|
-
`Your final assistant text before that tool call may explain your work,`,
|
|
15168
|
-
`but the submit-tool call itself must be your VERY LAST action.`,
|
|
15169
|
-
"",
|
|
15170
|
-
`Task artifacts: when you produce large files, binary files, logs, reports,`,
|
|
15171
|
-
`screenshots, traces, bundles, or datasets, save them in the task workspace`,
|
|
15172
|
-
`and call \`moltnet_upload_task_artifact\` before the submit-output tool.`,
|
|
15173
|
-
`Put the returned artifact CID in the structured output where the schema`,
|
|
15174
|
-
`allows artifact metadata (for example \`artifacts[].cid\`). Do not paste`,
|
|
15175
|
-
`large bytes into structured output.`,
|
|
15176
|
-
"",
|
|
15177
|
-
`Referenced inputs: if this task depends on prior task artifacts, call`,
|
|
15178
|
-
`\`moltnet_list_task_artifacts\` for the referenced task and download the`,
|
|
15179
|
-
`specific CID you need with \`moltnet_download_task_artifact\` before judging`,
|
|
15180
|
-
`or continuing that work.`,
|
|
15181
|
-
`For a bound input artifact, omit \`attemptN\` because it has no producing`,
|
|
15182
|
-
`attempt. Pass \`attemptN\` only for an artifact from one exact task attempt.`,
|
|
15183
|
-
"",
|
|
15184
|
-
`Output shape:`,
|
|
15185
|
-
"",
|
|
15186
|
-
"```json",
|
|
15187
|
-
shapeSketch,
|
|
15188
|
-
"```"
|
|
15189
|
-
];
|
|
15190
|
-
if (extraNotes?.length) {
|
|
15191
|
-
lines.push("");
|
|
15192
|
-
for (const note of extraNotes) lines.push(note);
|
|
15193
|
-
}
|
|
15194
|
-
return lines.join("\n");
|
|
15195
|
-
}
|
|
15196
|
-
//#endregion
|
|
15197
|
-
//#region ../agent-runtime/src/prompts/proactive-memory.ts
|
|
15198
|
-
function buildProactiveMemoryWorkflowBlock() {
|
|
15199
|
-
return [
|
|
15200
|
-
"Before material work, apply the runtime instructor's proactive memory",
|
|
15201
|
-
"rules instead of waiting for a human prompt. Start with constrained",
|
|
15202
|
-
"diary context: inspect tags/list entries when task provenance or scope",
|
|
15203
|
-
"tags are known, then use `moltnet_search_entries` with `taskFilter`,",
|
|
15204
|
-
"`entryTypes`, and tags. Do not run broad unfiltered searches before",
|
|
15205
|
-
"constrained searches miss.",
|
|
15206
|
-
"",
|
|
15207
|
-
"For incident capture, follow the runtime instructor exactly: search",
|
|
15208
|
-
"for similar episodic/semantic entries first, reference close matches,",
|
|
15209
|
-
"and create a recurrence entry only when the repeat is useful signal."
|
|
15210
|
-
].join("\n");
|
|
15211
|
-
}
|
|
15212
|
-
//#endregion
|
|
15213
15213
|
//#region ../agent-runtime/src/prompts/rubric-common.ts
|
|
15214
15214
|
function renderRubricCriteriaList(rubric) {
|
|
15215
15215
|
return rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
|
|
@@ -15289,9 +15289,7 @@ function buildAssessBriefUserPrompt(input, ctx) {
|
|
|
15289
15289
|
const scoring = [
|
|
15290
15290
|
"- `llm_score`: score 0..1 continuous. `rationale` REQUIRED (2–4 sentences).",
|
|
15291
15291
|
"- `boolean`: score exactly 0 or 1. `rationale` optional.",
|
|
15292
|
-
"- `deterministic_signature_check`: run `moltnet entry verify` on every diary entry returned by step 3 above AND `git verify-commit` on every commit. Score 1 iff ALL signatures are valid; otherwise 0. Populate `evidence.commitsVerified`, `evidence.commitsTotal`, `evidence.signatureFailures`."
|
|
15293
|
-
"",
|
|
15294
|
-
"Write a signed diary entry (tags: \"judgment\", \"assess_brief\") capturing the rationale before reporting structured output."
|
|
15292
|
+
"- `deterministic_signature_check`: run `moltnet entry verify` on every diary entry returned by step 3 above AND `git verify-commit` on every commit. Score 1 iff ALL signatures are valid; otherwise 0. Populate `evidence.commitsVerified`, `evidence.commitsTotal`, `evidence.signatureFailures`."
|
|
15295
15293
|
].join("\n");
|
|
15296
15294
|
return assembleTaskPrompt("assess_brief", [
|
|
15297
15295
|
{
|
|
@@ -15311,12 +15309,6 @@ function buildAssessBriefUserPrompt(input, ctx) {
|
|
|
15311
15309
|
header: "Querying the producer's diary entries",
|
|
15312
15310
|
body: diaryQuery
|
|
15313
15311
|
},
|
|
15314
|
-
{
|
|
15315
|
-
id: "assess_brief.proactive_memory",
|
|
15316
|
-
source: "discipline",
|
|
15317
|
-
header: "Proactive memory use",
|
|
15318
|
-
body: buildProactiveMemoryWorkflowBlock()
|
|
15319
|
-
},
|
|
15320
15312
|
{
|
|
15321
15313
|
id: "assess_brief.workspace",
|
|
15322
15314
|
source: "workspace",
|
|
@@ -15339,88 +15331,10 @@ function buildAssessBriefUserPrompt(input, ctx) {
|
|
|
15339
15331
|
source: "rubric_judge",
|
|
15340
15332
|
header: "Scoring rules",
|
|
15341
15333
|
body: scoring
|
|
15342
|
-
},
|
|
15343
|
-
{
|
|
15344
|
-
id: "assess_brief.final_output",
|
|
15345
|
-
source: "final_output",
|
|
15346
|
-
body: buildFinalOutputBlock({
|
|
15347
|
-
taskType: "assess_brief",
|
|
15348
|
-
outputSchemaName: "AssessBriefOutput",
|
|
15349
|
-
shapeSketch: [
|
|
15350
|
-
"{",
|
|
15351
|
-
" \"scores\": [",
|
|
15352
|
-
" { \"criterionId\": \"...\", \"score\": 0.0, \"rationale\": \"...\", \"evidence\": {} }",
|
|
15353
|
-
" ],",
|
|
15354
|
-
" \"composite\": <sum>,",
|
|
15355
|
-
" \"verdict\": \"<1-3 sentence overall>\",",
|
|
15356
|
-
" \"judgeModel\": \"<provider:model>\"",
|
|
15357
|
-
"}"
|
|
15358
|
-
].join("\n"),
|
|
15359
|
-
extraNotes: ["`composite` = Σ(weight_i × score_i) recomputed. The runtime rejects a mismatch."]
|
|
15360
|
-
})
|
|
15361
15334
|
}
|
|
15362
15335
|
]);
|
|
15363
15336
|
}
|
|
15364
15337
|
//#endregion
|
|
15365
|
-
//#region ../agent-runtime/src/prompts/self-verification.ts
|
|
15366
|
-
function buildSelfVerificationBlock(taskId, criteriaField = "successCriteria") {
|
|
15367
|
-
return [
|
|
15368
|
-
"## Self-verification",
|
|
15369
|
-
"",
|
|
15370
|
-
`If \`input.${criteriaField}\` is set on this task, your final output MUST`,
|
|
15371
|
-
"include a `verification` block. Treat every item in those criteria as",
|
|
15372
|
-
"part of the promise you made when you claimed the task. That includes",
|
|
15373
|
-
"the built-in submit-output gate when present. Do not call the submit",
|
|
15374
|
-
"tool until you have computed the verification payload you can honestly",
|
|
15375
|
-
"stand behind.",
|
|
15376
|
-
"",
|
|
15377
|
-
`Call \`moltnet_get_task\` with task id \`${taskId}\` and read \`input.${criteriaField}\`.`,
|
|
15378
|
-
"",
|
|
15379
|
-
`- If \`input.${criteriaField}\` is **absent**, omit \`verification\` from your`,
|
|
15380
|
-
" final output entirely.",
|
|
15381
|
-
`- If \`input.${criteriaField}\` is **present**, evaluate every applicable`,
|
|
15382
|
-
" item — `gates`, `assertions`, `rubric` criteria, `sideEffects` — against",
|
|
15383
|
-
" your produced work and emit one result per id. Be honest: a `fail` with",
|
|
15384
|
-
" a one-line reason is more useful than a false `pass`. Use `skip` (with a",
|
|
15385
|
-
" `detail`) when you genuinely could not determine a result. Compute",
|
|
15386
|
-
" `passed = results.every(r => r.status !== 'fail')`.",
|
|
15387
|
-
"- `verification` MUST be a JSON object. Never send a string, markdown",
|
|
15388
|
-
" block, null, or an empty placeholder. The submit tool expects an object",
|
|
15389
|
-
" with `inputCid`, `results`, and `passed` fields.",
|
|
15390
|
-
"",
|
|
15391
|
-
"Verification shape:",
|
|
15392
|
-
"",
|
|
15393
|
-
"```json",
|
|
15394
|
-
"{",
|
|
15395
|
-
" \"inputCid\": \"<the inputCid you saw on the task>\",",
|
|
15396
|
-
" \"results\": [",
|
|
15397
|
-
" { \"id\": \"<criterion id>\", \"kind\": \"assertion|gate|rubric|sideEffect\",",
|
|
15398
|
-
" \"status\": \"pass|fail|skip\", \"detail\": \"<optional one-liner>\" }",
|
|
15399
|
-
" ],",
|
|
15400
|
-
" \"passed\": <boolean>",
|
|
15401
|
-
"}",
|
|
15402
|
-
"```",
|
|
15403
|
-
"",
|
|
15404
|
-
"Minimal valid example:",
|
|
15405
|
-
"",
|
|
15406
|
-
"```json",
|
|
15407
|
-
"{",
|
|
15408
|
-
" \"inputCid\": \"<task inputCid>\",",
|
|
15409
|
-
" \"results\": [",
|
|
15410
|
-
" {",
|
|
15411
|
-
" \"id\": \"<criterion id>\",",
|
|
15412
|
-
" \"kind\": \"rubric\",",
|
|
15413
|
-
" \"status\": \"pass\",",
|
|
15414
|
-
" \"detail\": \"one-line reason\"",
|
|
15415
|
-
" }",
|
|
15416
|
-
" ],",
|
|
15417
|
-
" \"passed\": true",
|
|
15418
|
-
"}",
|
|
15419
|
-
"```",
|
|
15420
|
-
""
|
|
15421
|
-
].join("\n");
|
|
15422
|
-
}
|
|
15423
|
-
//#endregion
|
|
15424
15338
|
//#region ../agent-runtime/src/prompts/curate-pack.ts
|
|
15425
15339
|
/**
|
|
15426
15340
|
* Build the first user-message prompt for a `curate_pack` task.
|
|
@@ -15578,34 +15492,6 @@ function buildCuratePackUserPrompt(input, ctx) {
|
|
|
15578
15492
|
source: "static",
|
|
15579
15493
|
header: "Hard constraints",
|
|
15580
15494
|
body: hardConstraints
|
|
15581
|
-
},
|
|
15582
|
-
{
|
|
15583
|
-
id: "curate_pack.verification",
|
|
15584
|
-
source: "verification",
|
|
15585
|
-
body: buildSelfVerificationBlock(ctx.taskId)
|
|
15586
|
-
},
|
|
15587
|
-
{
|
|
15588
|
-
id: "curate_pack.final_output",
|
|
15589
|
-
source: "final_output",
|
|
15590
|
-
body: buildFinalOutputBlock({
|
|
15591
|
-
taskType: "curate_pack",
|
|
15592
|
-
outputSchemaName: "CuratePackOutput",
|
|
15593
|
-
shapeSketch: [
|
|
15594
|
-
"{",
|
|
15595
|
-
" \"packId\": \"<uuid>\",",
|
|
15596
|
-
" \"packCid\": \"<cid>\",",
|
|
15597
|
-
" \"entries\": [",
|
|
15598
|
-
" { \"entryId\": \"<uuid>\", \"rank\": 1, \"rationale\": \"<why>\" }",
|
|
15599
|
-
" ],",
|
|
15600
|
-
" \"recipeParams\": { \"recipe\": \"...\", \"prompt\": \"...\", ... },",
|
|
15601
|
-
" \"checkpoints\": [",
|
|
15602
|
-
" { \"phase\": \"recon\", \"candidateIds\": [...], \"droppedIds\": [...], \"notes\": \"...\" }",
|
|
15603
|
-
" ],",
|
|
15604
|
-
" \"summary\": \"<2-4 sentences: what you looked for, how you narrowed, what defines the final set>\",",
|
|
15605
|
-
" \"verification\": <required iff input.successCriteria; see Self-verification>",
|
|
15606
|
-
"}"
|
|
15607
|
-
].join("\n")
|
|
15608
|
-
})
|
|
15609
15495
|
}
|
|
15610
15496
|
]);
|
|
15611
15497
|
}
|
|
@@ -15642,16 +15528,13 @@ function buildFreeformUserPrompt(input, ctx) {
|
|
|
15642
15528
|
const expectedOutput = input.expectedOutput ?? "";
|
|
15643
15529
|
const constraints = input.constraints?.length ? input.constraints.map((constraint) => `- ${constraint}`).join("\n") : "";
|
|
15644
15530
|
const suggestedTaskType = input.suggestedTaskType ? [`The proposer suggested task type \`${input.suggestedTaskType}\`.`, "Use it as a hint, not as a contract."].join("\n") : "";
|
|
15645
|
-
const
|
|
15646
|
-
"
|
|
15647
|
-
"
|
|
15648
|
-
"
|
|
15649
|
-
"
|
|
15650
|
-
"
|
|
15651
|
-
"
|
|
15652
|
-
" `proposedTaskType` in the final output with a concise rationale.",
|
|
15653
|
-
"6. If you changed code on a branch, include that branch in",
|
|
15654
|
-
" `branch` so future continuations can recover git context."
|
|
15531
|
+
const outcomeHints = [
|
|
15532
|
+
"Complete the brief using the supplied task facts, context, and effective",
|
|
15533
|
+
"runtime capabilities.",
|
|
15534
|
+
"If the request reveals a recurring task shape, populate the",
|
|
15535
|
+
"`proposedTaskType` field exposed by the registered submit-output tool.",
|
|
15536
|
+
"If you changed code on a branch, populate its `branch` field so a",
|
|
15537
|
+
"continuation can recover that git context."
|
|
15655
15538
|
].join("\n");
|
|
15656
15539
|
const sections = [
|
|
15657
15540
|
{
|
|
@@ -15684,43 +15567,14 @@ function buildFreeformUserPrompt(input, ctx) {
|
|
|
15684
15567
|
body: suggestedTaskType
|
|
15685
15568
|
},
|
|
15686
15569
|
{
|
|
15687
|
-
id: "freeform.
|
|
15570
|
+
id: "freeform.outcome_hints",
|
|
15688
15571
|
source: "static",
|
|
15689
|
-
header: "
|
|
15690
|
-
body:
|
|
15691
|
-
},
|
|
15692
|
-
{
|
|
15693
|
-
id: "freeform.proactive_memory",
|
|
15694
|
-
source: "discipline",
|
|
15695
|
-
header: "Proactive memory use",
|
|
15696
|
-
body: buildProactiveMemoryWorkflowBlock()
|
|
15697
|
-
},
|
|
15698
|
-
{
|
|
15699
|
-
id: "freeform.verification",
|
|
15700
|
-
source: "verification",
|
|
15701
|
-
body: buildSelfVerificationBlock(ctx.taskId)
|
|
15702
|
-
},
|
|
15703
|
-
{
|
|
15704
|
-
id: "freeform.final_output",
|
|
15705
|
-
source: "final_output",
|
|
15706
|
-
body: buildFinalOutputBlock({
|
|
15707
|
-
taskType: "freeform",
|
|
15708
|
-
outputSchemaName: "FreeformOutput",
|
|
15709
|
-
shapeSketch: [
|
|
15710
|
-
"{",
|
|
15711
|
-
" \"summary\": \"<2-5 sentence result>\",",
|
|
15712
|
-
" \"branch\": \"<branch name when code changed; omit for prose-only work>\",",
|
|
15713
|
-
" \"artifacts\": [{ \"kind\": \"...\", \"title\": \"...\", \"description\": \"...\", \"body\": \"<inline content up to 64 KiB; preferred for textual output so it persists with the task>\", \"url\": \"...\", \"path\": \"<worktree-ephemeral; not persisted after completion>\" }],",
|
|
15714
|
-
" \"proposedTaskType\": { \"name\": \"...\", \"rationale\": \"...\", \"inputShape\": {}, \"outputShape\": {} },",
|
|
15715
|
-
" \"diaryEntryIds\": [\"...\"],",
|
|
15716
|
-
" \"verification\": <required iff input.successCriteria; see Self-verification>",
|
|
15717
|
-
"}"
|
|
15718
|
-
].join("\n")
|
|
15719
|
-
})
|
|
15572
|
+
header: "Outcome hints",
|
|
15573
|
+
body: outcomeHints
|
|
15720
15574
|
}
|
|
15721
15575
|
];
|
|
15722
15576
|
const priorContextBody = buildPriorContextSection(ctx.priorContext);
|
|
15723
|
-
if (priorContextBody) sections.
|
|
15577
|
+
if (priorContextBody) sections.push({
|
|
15724
15578
|
id: "freeform.prior_context",
|
|
15725
15579
|
source: "task_input",
|
|
15726
15580
|
body: priorContextBody
|
|
@@ -15737,22 +15591,18 @@ function buildFreeformUserPrompt(input, ctx) {
|
|
|
15737
15591
|
* is told to inspect them itself.
|
|
15738
15592
|
*/
|
|
15739
15593
|
function buildFulfillBriefUserPrompt(input, ctx) {
|
|
15740
|
-
const { brief, seedFiles
|
|
15594
|
+
const { brief, seedFiles } = input;
|
|
15741
15595
|
const header = [
|
|
15742
15596
|
"# Fulfill Brief Agent",
|
|
15743
15597
|
"",
|
|
15744
15598
|
"You are a software engineering agent working in a sandboxed environment.",
|
|
15745
15599
|
"Use the current working directory as the task workspace.",
|
|
15746
|
-
"The MoltNet runtime instructor (above, in this system prompt) defines the",
|
|
15747
|
-
"invariants for this task: identity, gh authentication, diary discipline,",
|
|
15748
|
-
"and the accountable-commit shape. Follow it for every commit.",
|
|
15749
15600
|
"",
|
|
15750
15601
|
"## Task: Fulfill brief",
|
|
15751
15602
|
"",
|
|
15752
15603
|
`Task id: \`${ctx.taskId}\``
|
|
15753
15604
|
].join("\n");
|
|
15754
15605
|
const seedFilesBody = seedFiles?.length ? ["Start by reading these files to ground yourself:", ...seedFiles.map((f) => `- \`${f}\``)].join("\n") : "";
|
|
15755
|
-
const branchSlug = ctx.correlationId ? `moltnet/${ctx.correlationId}/` : scopeHint ? `feat/${scopeHint}-` : "feat/";
|
|
15756
15606
|
const correlation = ctx.correlationId ? [
|
|
15757
15607
|
`This task carries correlationId \`${ctx.correlationId}\`. You MUST:`,
|
|
15758
15608
|
"",
|
|
@@ -15769,23 +15619,6 @@ function buildFulfillBriefUserPrompt(input, ctx) {
|
|
|
15769
15619
|
"for this task. Do not repurpose or switch the primary checkout.",
|
|
15770
15620
|
ctx.workspace.branch ? `The current branch is \`${ctx.workspace.branch}\`. Stay on this branch unless the runtime instructor explicitly tells you otherwise.` : "Stay on the branch that was pre-provisioned for this task."
|
|
15771
15621
|
].join("\n") : "";
|
|
15772
|
-
const workflow = [
|
|
15773
|
-
ctx.workspace?.mode === "dedicated_worktree" ? `1. Use the already-provisioned dedicated worktree branch${ctx.workspace.branch ? ` (\`${ctx.workspace.branch}\`)` : ""}; do not create or switch the primary checkout.` : `1. Create a feature branch (starting prefix suggestion: \`${branchSlug}<short-slug>\`).`,
|
|
15774
|
-
"2. Search MoltNet diary memory for prior decisions, incidents, and",
|
|
15775
|
-
" recurring traps relevant to the brief before changing code.",
|
|
15776
|
-
"3. Understand the problem — read relevant code; do not speculate.",
|
|
15777
|
-
"4. Implement the change. Keep commits small and coherent.",
|
|
15778
|
-
"5. Add tests if applicable.",
|
|
15779
|
-
"6. For every commit, create a signed diary entry first via",
|
|
15780
|
-
" `moltnet_create_entry` and embed its id in the commit trailer",
|
|
15781
|
-
" `MoltNet-Diary: <id>` (per the runtime instructor).",
|
|
15782
|
-
"7. Push the branch and open a PR — run `git push` and `gh pr create`",
|
|
15783
|
-
" IN the VM with your normal `bash` tool (use the",
|
|
15784
|
-
" `GH_TOKEN=$(moltnet github token …) gh …` form from the runtime",
|
|
15785
|
-
" instructor for writes; read-only `gh` commands may run bare). Do NOT",
|
|
15786
|
-
" use `moltnet_host_exec` for this; it needs human",
|
|
15787
|
-
" approval that is unavailable in a headless run."
|
|
15788
|
-
].join("\n");
|
|
15789
15622
|
return assembleTaskPrompt("fulfill_brief", [
|
|
15790
15623
|
{
|
|
15791
15624
|
id: "fulfill_brief.header",
|
|
@@ -15815,41 +15648,6 @@ function buildFulfillBriefUserPrompt(input, ctx) {
|
|
|
15815
15648
|
source: "workspace",
|
|
15816
15649
|
header: "Workspace",
|
|
15817
15650
|
body: workspace
|
|
15818
|
-
},
|
|
15819
|
-
{
|
|
15820
|
-
id: "fulfill_brief.workflow",
|
|
15821
|
-
source: "static",
|
|
15822
|
-
header: "Workflow",
|
|
15823
|
-
body: workflow
|
|
15824
|
-
},
|
|
15825
|
-
{
|
|
15826
|
-
id: "fulfill_brief.proactive_memory",
|
|
15827
|
-
source: "discipline",
|
|
15828
|
-
header: "Proactive memory use",
|
|
15829
|
-
body: buildProactiveMemoryWorkflowBlock()
|
|
15830
|
-
},
|
|
15831
|
-
{
|
|
15832
|
-
id: "fulfill_brief.verification",
|
|
15833
|
-
source: "verification",
|
|
15834
|
-
body: buildSelfVerificationBlock(ctx.taskId)
|
|
15835
|
-
},
|
|
15836
|
-
{
|
|
15837
|
-
id: "fulfill_brief.final_output",
|
|
15838
|
-
source: "final_output",
|
|
15839
|
-
body: buildFinalOutputBlock({
|
|
15840
|
-
taskType: "fulfill_brief",
|
|
15841
|
-
outputSchemaName: "FulfillBriefOutput",
|
|
15842
|
-
shapeSketch: [
|
|
15843
|
-
"{",
|
|
15844
|
-
" \"branch\": \"<branch-name>\",",
|
|
15845
|
-
" \"commits\": [{ \"sha\": \"...\", \"message\": \"...\", \"diaryEntryId\": \"...\" }],",
|
|
15846
|
-
" \"pullRequestUrl\": \"<url-or-null>\",",
|
|
15847
|
-
" \"diaryEntryIds\": [\"...\"],",
|
|
15848
|
-
" \"summary\": \"<1-3 sentence recap>\",",
|
|
15849
|
-
" \"verification\": <required iff input.successCriteria; see Self-verification>",
|
|
15850
|
-
"}"
|
|
15851
|
-
].join("\n")
|
|
15852
|
-
})
|
|
15853
15651
|
}
|
|
15854
15652
|
]);
|
|
15855
15653
|
}
|
|
@@ -15926,26 +15724,6 @@ function buildJudgeEvalAttemptUserPrompt(input, ctx) {
|
|
|
15926
15724
|
source: "rubric_judge",
|
|
15927
15725
|
header: "Composite arithmetic",
|
|
15928
15726
|
body: composite
|
|
15929
|
-
},
|
|
15930
|
-
{
|
|
15931
|
-
id: "judge_eval_attempt.final_output",
|
|
15932
|
-
source: "final_output",
|
|
15933
|
-
body: buildFinalOutputBlock({
|
|
15934
|
-
taskType: "judge_eval_attempt",
|
|
15935
|
-
outputSchemaName: "JudgeEvalAttemptOutput",
|
|
15936
|
-
shapeSketch: [
|
|
15937
|
-
"{",
|
|
15938
|
-
` "targetTaskId": "${input.targetTaskId}",`,
|
|
15939
|
-
` "targetAttemptN": ${input.targetAttemptN},`,
|
|
15940
|
-
" \"variantLabel\": \"<from producer input>\",",
|
|
15941
|
-
" \"scores\": [ { \"criterionId\": \"...\", \"score\": 0..1, \"rationale\": \"...\", \"assertions\": [...]?, \"evidence\": { \"text\": \"...\" } } ],",
|
|
15942
|
-
" \"composite\": <Σ(weight × score), 0..1>,",
|
|
15943
|
-
" \"verdict\": \"<1-3 sentences>\",",
|
|
15944
|
-
" \"judgeModel\": \"<id>\", // optional",
|
|
15945
|
-
" \"traceparent\": \"<from claim>\"",
|
|
15946
|
-
"}"
|
|
15947
|
-
].join("\n")
|
|
15948
|
-
})
|
|
15949
15727
|
}
|
|
15950
15728
|
]);
|
|
15951
15729
|
}
|
|
@@ -16027,9 +15805,7 @@ function buildJudgePackUserPrompt(input, ctx) {
|
|
|
16027
15805
|
"- Do NOT call `moltnet_pack_create` or `moltnet_pack_render`.",
|
|
16028
15806
|
"- Do NOT fetch the curator's or renderer's task output directly — they",
|
|
16029
15807
|
" may leak guidance that biases judgment.",
|
|
16030
|
-
"- Keep the session focused on scoring; no speculative exploration."
|
|
16031
|
-
"",
|
|
16032
|
-
`Write a signed diary entry (tags: \`judgment\`, \`judge_pack\`, \`rubric:${rubric.rubricId}\`) capturing the rationale before reporting structured output.`
|
|
15808
|
+
"- Keep the session focused on scoring; no speculative exploration."
|
|
16033
15809
|
].join("\n");
|
|
16034
15810
|
return assembleTaskPrompt("judge_pack", [
|
|
16035
15811
|
{
|
|
@@ -16071,37 +15847,6 @@ function buildJudgePackUserPrompt(input, ctx) {
|
|
|
16071
15847
|
source: "static",
|
|
16072
15848
|
header: "Constraints",
|
|
16073
15849
|
body: constraints
|
|
16074
|
-
},
|
|
16075
|
-
{
|
|
16076
|
-
id: "judge_pack.final_output",
|
|
16077
|
-
source: "final_output",
|
|
16078
|
-
body: buildFinalOutputBlock({
|
|
16079
|
-
taskType: "judge_pack",
|
|
16080
|
-
outputSchemaName: "JudgePackOutput",
|
|
16081
|
-
shapeSketch: [
|
|
16082
|
-
"{",
|
|
16083
|
-
" \"scores\": [",
|
|
16084
|
-
" { \"criterionId\": \"...\", \"score\": 0.0, \"rationale\": \"...\", \"evidence\": {} },",
|
|
16085
|
-
" {",
|
|
16086
|
-
" \"criterionId\": \"<llm_checklist criterion>\",",
|
|
16087
|
-
" \"score\": 0, // 1 iff every assertion passed",
|
|
16088
|
-
" \"assertions\": [",
|
|
16089
|
-
" { \"id\": \"claim-1\", \"text\": \"...\", \"passed\": false, \"evidence\": \"...\" }",
|
|
16090
|
-
" ]",
|
|
16091
|
-
" }",
|
|
16092
|
-
" ],",
|
|
16093
|
-
" \"composite\": <sum-of-weighted-scores>,",
|
|
16094
|
-
" \"verdict\": \"<1-3 sentence overall>\",",
|
|
16095
|
-
" \"judgeModel\": \"<provider:model>\",",
|
|
16096
|
-
" \"rendererBinaryCid\": \"<cid-string-only-if-available>\"",
|
|
16097
|
-
"}"
|
|
16098
|
-
].join("\n"),
|
|
16099
|
-
extraNotes: [
|
|
16100
|
-
"Omit `rendererBinaryCid` entirely when no binary CID is exposed by",
|
|
16101
|
-
"`moltnet_rendered_pack_get`. Do NOT emit `null` — the field is",
|
|
16102
|
-
"optional and absence is the correct representation when unavailable."
|
|
16103
|
-
]
|
|
16104
|
-
})
|
|
16105
15850
|
}
|
|
16106
15851
|
]);
|
|
16107
15852
|
}
|
|
@@ -16144,20 +15889,6 @@ function buildPrReviewUserPrompt(input, ctx) {
|
|
|
16144
15889
|
"(for example publishing the judgment somewhere), perform that action as",
|
|
16145
15890
|
"part of the task before reporting structured output."
|
|
16146
15891
|
].join("\n");
|
|
16147
|
-
const workflow = [
|
|
16148
|
-
"1. Read the subject summary, resources, inspection hints, and any",
|
|
16149
|
-
" task-specific instructions before scoring.",
|
|
16150
|
-
"2. Search MoltNet diary memory for prior decisions, incidents, and",
|
|
16151
|
-
" recurring review traps relevant to the subject.",
|
|
16152
|
-
"3. Inspect the target artefact directly using the tools and resources the",
|
|
16153
|
-
" task makes available.",
|
|
16154
|
-
"4. If you are in a dedicated disposable worktree and need the review target",
|
|
16155
|
-
" checked out locally, do that work inside this disposable workspace only.",
|
|
16156
|
-
"5. Apply the rubric strictly. This task is about complexity and",
|
|
16157
|
-
" reviewability, not correctness or feature desirability.",
|
|
16158
|
-
"6. Perform any required outward action before emitting the final",
|
|
16159
|
-
" structured output."
|
|
16160
|
-
].join("\n");
|
|
16161
15892
|
const taskPromptSection = input.taskPrompt ?? "";
|
|
16162
15893
|
const preamble = renderRubricPreambleSection(rubric) ?? "";
|
|
16163
15894
|
const criteria = renderRubricCriteriaList(rubric);
|
|
@@ -16166,9 +15897,7 @@ function buildPrReviewUserPrompt(input, ctx) {
|
|
|
16166
15897
|
"- Score `1` when the subject clearly clears the criterion.",
|
|
16167
15898
|
"- Score `0` when it does not, or when the evidence is ambiguous.",
|
|
16168
15899
|
"- `rationale` is REQUIRED for every score. Keep it concrete and audit-friendly.",
|
|
16169
|
-
"- Compute `composite = Σ(weight_i × score_i)` exactly; the runtime rejects mismatches."
|
|
16170
|
-
"",
|
|
16171
|
-
"Write a signed diary entry (tags: `judgment`, `pr_review`) capturing the rationale before reporting structured output."
|
|
15900
|
+
"- Compute `composite = Σ(weight_i × score_i)` exactly; the runtime rejects mismatches."
|
|
16172
15901
|
].join("\n");
|
|
16173
15902
|
return assembleTaskPrompt("pr_review", [
|
|
16174
15903
|
{
|
|
@@ -16206,18 +15935,6 @@ function buildPrReviewUserPrompt(input, ctx) {
|
|
|
16206
15935
|
header: "Execution contract",
|
|
16207
15936
|
body: executionContract
|
|
16208
15937
|
},
|
|
16209
|
-
{
|
|
16210
|
-
id: "pr_review.workflow",
|
|
16211
|
-
source: "static",
|
|
16212
|
-
header: "Review workflow",
|
|
16213
|
-
body: workflow
|
|
16214
|
-
},
|
|
16215
|
-
{
|
|
16216
|
-
id: "pr_review.proactive_memory",
|
|
16217
|
-
source: "discipline",
|
|
16218
|
-
header: "Proactive memory use",
|
|
16219
|
-
body: buildProactiveMemoryWorkflowBlock()
|
|
16220
|
-
},
|
|
16221
15938
|
{
|
|
16222
15939
|
id: "pr_review.task_prompt",
|
|
16223
15940
|
source: "task_input",
|
|
@@ -16240,24 +15957,6 @@ function buildPrReviewUserPrompt(input, ctx) {
|
|
|
16240
15957
|
source: "rubric_judge",
|
|
16241
15958
|
header: "Scoring rules",
|
|
16242
15959
|
body: scoring
|
|
16243
|
-
},
|
|
16244
|
-
{
|
|
16245
|
-
id: "pr_review.final_output",
|
|
16246
|
-
source: "final_output",
|
|
16247
|
-
body: buildFinalOutputBlock({
|
|
16248
|
-
taskType: "pr_review",
|
|
16249
|
-
outputSchemaName: "PrReviewOutput",
|
|
16250
|
-
shapeSketch: [
|
|
16251
|
-
"{",
|
|
16252
|
-
" \"scores\": [",
|
|
16253
|
-
" { \"criterionId\": \"...\", \"score\": 0, \"rationale\": \"...\" }",
|
|
16254
|
-
" ],",
|
|
16255
|
-
" \"composite\": <sum-of-weighted-binary-scores>,",
|
|
16256
|
-
" \"verdict\": \"<1-3 sentence overall>\"",
|
|
16257
|
-
"}"
|
|
16258
|
-
].join("\n"),
|
|
16259
|
-
extraNotes: ["`scores` MUST stay in the same order as the rubric criteria.", "`score` MUST be exactly `0` or `1` for every criterion."]
|
|
16260
|
-
})
|
|
16261
15960
|
}
|
|
16262
15961
|
]);
|
|
16263
15962
|
}
|
|
@@ -16350,30 +16049,6 @@ function buildRenderPackUserPrompt(input, ctx) {
|
|
|
16350
16049
|
source: "static",
|
|
16351
16050
|
header: "Fidelity Discipline",
|
|
16352
16051
|
body: fidelity
|
|
16353
|
-
},
|
|
16354
|
-
{
|
|
16355
|
-
id: "render_pack.verification",
|
|
16356
|
-
source: "verification",
|
|
16357
|
-
body: buildSelfVerificationBlock(ctx.taskId)
|
|
16358
|
-
},
|
|
16359
|
-
{
|
|
16360
|
-
id: "render_pack.final_output",
|
|
16361
|
-
source: "final_output",
|
|
16362
|
-
body: buildFinalOutputBlock({
|
|
16363
|
-
taskType: "render_pack",
|
|
16364
|
-
outputSchemaName: "RenderPackOutput",
|
|
16365
|
-
shapeSketch: [
|
|
16366
|
-
"{",
|
|
16367
|
-
" \"renderedPackId\": \"<uuid-or-null>\",",
|
|
16368
|
-
" \"renderedCid\": \"<cid>\",",
|
|
16369
|
-
" \"renderMethod\": \"<label>\",",
|
|
16370
|
-
" \"byteSize\": <int>,",
|
|
16371
|
-
" \"entriesRendered\": <int>,",
|
|
16372
|
-
" \"summary\": \"<1-3 sentence recap>\",",
|
|
16373
|
-
" \"verification\": <required iff input.successCriteria; see Self-verification>",
|
|
16374
|
-
"}"
|
|
16375
|
-
].join("\n")
|
|
16376
|
-
})
|
|
16377
16052
|
}
|
|
16378
16053
|
]);
|
|
16379
16054
|
}
|
|
@@ -16408,7 +16083,7 @@ function buildRenderPackUserPrompt(input, ctx) {
|
|
|
16408
16083
|
* field. Quoting the constraint back is not following the task.
|
|
16409
16084
|
*/
|
|
16410
16085
|
function buildRunEvalUserPrompt(input, ctx) {
|
|
16411
|
-
const { scenario, variantLabel
|
|
16086
|
+
const { scenario, variantLabel } = input;
|
|
16412
16087
|
const effectiveRuntimeContext = ctx.effectiveRuntimeContext ?? input.context;
|
|
16413
16088
|
const hasContext = effectiveRuntimeContext.length > 0;
|
|
16414
16089
|
const hasInlineContext = effectiveRuntimeContext.some((entry) => entry.binding === "context_inline");
|
|
@@ -16429,27 +16104,6 @@ function buildRunEvalUserPrompt(input, ctx) {
|
|
|
16429
16104
|
"rules, those rules override your generic instincts."
|
|
16430
16105
|
].join("\n") : "";
|
|
16431
16106
|
const inputFiles = scenario.inputFiles?.length ? scenario.inputFiles.map((f) => `- \`${f}\``).join("\n") : "";
|
|
16432
|
-
const verification = successCriteria ? buildSelfVerificationBlock(ctx.taskId) : "";
|
|
16433
|
-
const finalOutput = buildFinalOutputBlock({
|
|
16434
|
-
taskType: "run_eval",
|
|
16435
|
-
outputSchemaName: "RunEvalOutput",
|
|
16436
|
-
shapeSketch: [
|
|
16437
|
-
"{",
|
|
16438
|
-
" \"response\": \"<your free-form answer>\",",
|
|
16439
|
-
" \"artifacts\": [{ \"path\": \"...\", \"cid\": \"...\" }], // optional",
|
|
16440
|
-
" \"totalTokens\": <int>,",
|
|
16441
|
-
" \"durationMs\": <int>,",
|
|
16442
|
-
" \"traceparent\": \"<from claim>\",",
|
|
16443
|
-
" \"verification\": {",
|
|
16444
|
-
" \"inputCid\": \"<task inputCid>\",",
|
|
16445
|
-
" \"results\": [",
|
|
16446
|
-
" { \"id\": \"<criterion id>\", \"kind\": \"rubric\", \"status\": \"pass|fail|skip\", \"detail\": \"<optional one-liner>\" }",
|
|
16447
|
-
" ],",
|
|
16448
|
-
" \"passed\": <boolean>",
|
|
16449
|
-
" } // required iff input.successCriteria; must be an object, never a string",
|
|
16450
|
-
"}"
|
|
16451
|
-
].join("\n")
|
|
16452
|
-
});
|
|
16453
16107
|
return assembleTaskPrompt("run_eval", [
|
|
16454
16108
|
{
|
|
16455
16109
|
id: "run_eval.header",
|
|
@@ -16473,16 +16127,6 @@ function buildRunEvalUserPrompt(input, ctx) {
|
|
|
16473
16127
|
source: "task_input",
|
|
16474
16128
|
header: "Input files",
|
|
16475
16129
|
body: inputFiles
|
|
16476
|
-
},
|
|
16477
|
-
{
|
|
16478
|
-
id: "run_eval.verification",
|
|
16479
|
-
source: "verification",
|
|
16480
|
-
body: verification
|
|
16481
|
-
},
|
|
16482
|
-
{
|
|
16483
|
-
id: "run_eval.final_output",
|
|
16484
|
-
source: "final_output",
|
|
16485
|
-
body: finalOutput
|
|
16486
16130
|
}
|
|
16487
16131
|
]);
|
|
16488
16132
|
}
|
|
@@ -16497,14 +16141,17 @@ function submissionAcceptsVerification(taskType) {
|
|
|
16497
16141
|
/**
|
|
16498
16142
|
* Add only the dynamic contract facts that a producer cannot infer from its
|
|
16499
16143
|
* task-specific prompt: the declared success criteria and the immutable input
|
|
16500
|
-
* CID its verification must cite.
|
|
16501
|
-
* the
|
|
16144
|
+
* provenance CID its verification must cite. The CID is not a task artifact,
|
|
16145
|
+
* so the prompt states that it cannot be downloaded. This is deliberately not
|
|
16146
|
+
* a workflow block; the submit tool owns the output shape and profiles own
|
|
16147
|
+
* optional behavior.
|
|
16502
16148
|
*/
|
|
16503
16149
|
function appendTaskContractFacts(prompt, task) {
|
|
16504
16150
|
if (!hasSuccessCriteria(task.input) || !submissionAcceptsVerification(task.taskType)) return prompt;
|
|
16505
16151
|
const criteriaJson = JSON.stringify(task.input.successCriteria, null, 2);
|
|
16506
16152
|
const body = [
|
|
16507
|
-
|
|
16153
|
+
"Task input verification CID (provenance only; this is not a task",
|
|
16154
|
+
`artifact and cannot be downloaded): \`${task.inputCid}\``,
|
|
16508
16155
|
"",
|
|
16509
16156
|
"These typed criteria are task facts. Assess the completed work against",
|
|
16510
16157
|
"them before calling the submit-output tool. Its `verification` payload",
|
|
@@ -31076,6 +30723,12 @@ var ShellCommandAnalyzer = class ShellCommandAnalyzer {
|
|
|
31076
30723
|
}
|
|
31077
30724
|
};
|
|
31078
30725
|
//#endregion
|
|
30726
|
+
//#region src/config.ts
|
|
30727
|
+
/** Resolve Pi's host-side auth/config directory from process configuration. */
|
|
30728
|
+
function resolvePiCodingAgentDir() {
|
|
30729
|
+
return process.env["PI_CODING_AGENT_DIR"] ?? path.join(homedir(), ".pi", "agent");
|
|
30730
|
+
}
|
|
30731
|
+
//#endregion
|
|
31079
30732
|
//#region src/snapshot.ts
|
|
31080
30733
|
/**
|
|
31081
30734
|
* Snapshot builder with auto-build and caching.
|
|
@@ -31456,15 +31109,19 @@ function filterModelVisibleTools(tools, policy) {
|
|
|
31456
31109
|
}
|
|
31457
31110
|
function enabledPiToolNames(input) {
|
|
31458
31111
|
if (!input.policy || input.policy.enforcement !== "enforce") return void 0;
|
|
31112
|
+
return modelVisiblePiToolNames(input);
|
|
31113
|
+
}
|
|
31114
|
+
/** Exact tool names the selected runtime and effective policy expose. */
|
|
31115
|
+
function modelVisiblePiToolNames(input) {
|
|
31459
31116
|
return [...new Set([...input.tools.map((tool) => tool.name), ...(input.extensions ?? []).flatMap((extension) => extension.declaredTools.filter((name) => isToolVisible(name, input.policy)))])].sort();
|
|
31460
31117
|
}
|
|
31461
31118
|
function isToolVisible(name, policy) {
|
|
31462
31119
|
if (!policy || policy.enforcement !== "enforce") return true;
|
|
31463
|
-
if (name === "bash") return
|
|
31120
|
+
if (name === "bash") return policy.allowedShellCommands === void 0 || policy.allowedShellCommands.length > 0;
|
|
31464
31121
|
return policy.allowedTools.has(name);
|
|
31465
31122
|
}
|
|
31466
31123
|
function isKernelTool(name) {
|
|
31467
|
-
return name.startsWith("submit_");
|
|
31124
|
+
return name.startsWith("submit_") || name === "subagent";
|
|
31468
31125
|
}
|
|
31469
31126
|
function wrapExtensionFactory(factory, contribution, policy) {
|
|
31470
31127
|
return (pi) => {
|
|
@@ -31482,7 +31139,7 @@ function wrapExtensionFactory(factory, contribution, policy) {
|
|
|
31482
31139
|
};
|
|
31483
31140
|
}
|
|
31484
31141
|
function claimToolName(names, name, owner) {
|
|
31485
|
-
if (isKernelTool(name)
|
|
31142
|
+
if (isKernelTool(name)) throw new Error(`Pi tool name "${name}" is reserved by the runtime kernel`);
|
|
31486
31143
|
const previous = names.get(name);
|
|
31487
31144
|
if (previous) throw new Error(`Pi tool name "${name}" is declared by ${previous} and ${owner}`);
|
|
31488
31145
|
names.set(name, owner);
|
|
@@ -31576,6 +31233,17 @@ async function delay(ms, signal, label) {
|
|
|
31576
31233
|
* investigation and the alternatives we rejected.
|
|
31577
31234
|
*/
|
|
31578
31235
|
var GUEST_TASK_CONTEXT_MOUNT = "/moltnet-task-context";
|
|
31236
|
+
function resolveVfsShadowConfig(config) {
|
|
31237
|
+
const patterns = config?.vfs?.shadow ?? [];
|
|
31238
|
+
if (patterns.length === 0) return {
|
|
31239
|
+
mode: "none",
|
|
31240
|
+
patterns: []
|
|
31241
|
+
};
|
|
31242
|
+
return {
|
|
31243
|
+
mode: config?.vfs?.shadowMode ?? "tmpfs",
|
|
31244
|
+
patterns
|
|
31245
|
+
};
|
|
31246
|
+
}
|
|
31579
31247
|
function shouldRunResumeCommand(entry, ctx) {
|
|
31580
31248
|
if (typeof entry === "string") return true;
|
|
31581
31249
|
const workspaceModes = entry.when?.workspaceMode;
|
|
@@ -31648,7 +31316,7 @@ function resolveVmAgentDir(config) {
|
|
|
31648
31316
|
function loadCredentials(agentDir) {
|
|
31649
31317
|
const moltnetJson = readFileSync(path.join(agentDir, "moltnet.json"), "utf8");
|
|
31650
31318
|
const agentEnvRaw = readFileSync(path.join(agentDir, "env"), "utf8");
|
|
31651
|
-
const piAgentDir =
|
|
31319
|
+
const piAgentDir = resolvePiCodingAgentDir();
|
|
31652
31320
|
const piAuthPath = path.join(piAgentDir, "auth.json");
|
|
31653
31321
|
const piAuthJson = existsSync(piAuthPath) ? readFileSync(piAuthPath, "utf8") : null;
|
|
31654
31322
|
const gitconfigPath = path.join(agentDir, "gitconfig");
|
|
@@ -31803,7 +31471,7 @@ async function resumeVm(config) {
|
|
|
31803
31471
|
else vmAgentEnv[k] = v;
|
|
31804
31472
|
}
|
|
31805
31473
|
vmAgentEnv.MOLTNET_CREDENTIALS_PATH = `${vmAgentDir}/moltnet.json`;
|
|
31806
|
-
const vfsConfig = config.sandboxConfig
|
|
31474
|
+
const vfsConfig = resolveVfsShadowConfig(config.sandboxConfig);
|
|
31807
31475
|
let workspaceProvider = new RealFSProvider(config.mountPath);
|
|
31808
31476
|
workspaceProvider = new ShadowProvider(workspaceProvider, {
|
|
31809
31477
|
shouldShadow: ({ path: shadowPath }) => shouldShadowNodeModulesPath(shadowPath),
|
|
@@ -31811,11 +31479,11 @@ async function resumeVm(config) {
|
|
|
31811
31479
|
tmpfs: new AutoParentMemoryProvider(),
|
|
31812
31480
|
writeMode: "tmpfs"
|
|
31813
31481
|
});
|
|
31814
|
-
if (vfsConfig
|
|
31815
|
-
const predicate = createShadowPathPredicate(vfsConfig.
|
|
31482
|
+
if (vfsConfig.mode !== "none") {
|
|
31483
|
+
const predicate = createShadowPathPredicate(vfsConfig.patterns);
|
|
31816
31484
|
workspaceProvider = new ShadowProvider(workspaceProvider, {
|
|
31817
31485
|
shouldShadow: predicate,
|
|
31818
|
-
writeMode: vfsConfig.
|
|
31486
|
+
writeMode: vfsConfig.mode
|
|
31819
31487
|
});
|
|
31820
31488
|
}
|
|
31821
31489
|
const forwardedEnv = {};
|
|
@@ -32275,7 +31943,7 @@ async function executeGondolinGrep(vm, localCwd, guestWorkspace, params, signal)
|
|
|
32275
31943
|
const onAbort = () => ac.abort();
|
|
32276
31944
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
32277
31945
|
try {
|
|
32278
|
-
const proc = vm.exec(["
|
|
31946
|
+
const proc = vm.exec(["rg", ...args], {
|
|
32279
31947
|
signal: ac.signal,
|
|
32280
31948
|
stdout: "pipe",
|
|
32281
31949
|
stderr: "pipe"
|
|
@@ -32428,6 +32096,7 @@ function createGondolinBashOps(vm, localCwd, guestWorkspace) {
|
|
|
32428
32096
|
*/
|
|
32429
32097
|
function decideToolCall(input) {
|
|
32430
32098
|
if (input.enforcement === "off") return { allow: true };
|
|
32099
|
+
if (input.toolName.startsWith("submit_") || input.toolName === "subagent") return { allow: true };
|
|
32431
32100
|
const resolved = resolveNames(input);
|
|
32432
32101
|
if (resolved.kind === "unresolvable") return fenced(input.enforcement, "shell command could not be statically authorized", "unresolvable shell command (watch)");
|
|
32433
32102
|
const arbitraryCode = [...new Set(resolved.tools.filter((tool) => tool.risk === "arbitrary-code").map((tool) => tool.name))];
|
|
@@ -32559,6 +32228,10 @@ async function resolveSessionToolPolicy(input) {
|
|
|
32559
32228
|
try {
|
|
32560
32229
|
const resolved = await withTimeout$1(input.agent.runtimeProfiles.allowedTools(input.profileId, { teamId: input.teamId }), timeoutMs);
|
|
32561
32230
|
const shellCommands = resolved.allowedShellCommands ?? [];
|
|
32231
|
+
if (resolved.runtimeKind !== input.runtimeKind) throw new RuntimeKindMismatchError({
|
|
32232
|
+
expectedRuntimeKind: input.runtimeKind,
|
|
32233
|
+
receivedRuntimeKind: resolved.runtimeKind
|
|
32234
|
+
});
|
|
32562
32235
|
return {
|
|
32563
32236
|
enforcement: resolved.enforcement,
|
|
32564
32237
|
allowedTools: new Set(resolved.allowedTools),
|
|
@@ -32592,6 +32265,12 @@ var ToolPolicyResolveTimeoutError = class extends Error {
|
|
|
32592
32265
|
this.name = "ToolPolicyResolveTimeoutError";
|
|
32593
32266
|
}
|
|
32594
32267
|
};
|
|
32268
|
+
var RuntimeKindMismatchError = class extends Error {
|
|
32269
|
+
constructor(input) {
|
|
32270
|
+
super(`runtime kind mismatch: expected ${input.expectedRuntimeKind}, received ${input.receivedRuntimeKind}`);
|
|
32271
|
+
this.name = "RuntimeKindMismatchError";
|
|
32272
|
+
}
|
|
32273
|
+
};
|
|
32595
32274
|
/**
|
|
32596
32275
|
* Reject with {@link ToolPolicyResolveTimeoutError} if `promise` does not settle
|
|
32597
32276
|
* within `timeoutMs`. A non-positive `timeoutMs` disables the deadline. The
|
|
@@ -32669,6 +32348,105 @@ function createToolPolicyExtension(deps) {
|
|
|
32669
32348
|
};
|
|
32670
32349
|
}
|
|
32671
32350
|
//#endregion
|
|
32351
|
+
//#region src/runtime/capability-discovery.ts
|
|
32352
|
+
var GuestExecutableProbeError = class extends Error {
|
|
32353
|
+
code;
|
|
32354
|
+
constructor(code, message, options) {
|
|
32355
|
+
super(message, options);
|
|
32356
|
+
this.name = "GuestExecutableProbeError";
|
|
32357
|
+
this.code = code;
|
|
32358
|
+
}
|
|
32359
|
+
};
|
|
32360
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 5e3;
|
|
32361
|
+
var MAX_STDERR_DETAIL_LENGTH = 1e3;
|
|
32362
|
+
/**
|
|
32363
|
+
* Verify only executables relevant to the resolved session policy.
|
|
32364
|
+
* Candidate names are positional arguments, never interpolated shell source.
|
|
32365
|
+
*/
|
|
32366
|
+
async function discoverGuestExecutables(vm, candidates, options = {}) {
|
|
32367
|
+
const unique = [...new Set(candidates)].sort();
|
|
32368
|
+
if (unique.length === 0) return {
|
|
32369
|
+
available: [],
|
|
32370
|
+
unavailable: []
|
|
32371
|
+
};
|
|
32372
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
32373
|
+
const controller = new AbortController();
|
|
32374
|
+
let timedOut = false;
|
|
32375
|
+
const timeout = setTimeout(() => {
|
|
32376
|
+
timedOut = true;
|
|
32377
|
+
controller.abort();
|
|
32378
|
+
}, timeoutMs);
|
|
32379
|
+
const abortFromCaller = () => controller.abort(options.signal?.reason);
|
|
32380
|
+
options.signal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
32381
|
+
if (options.signal?.aborted) abortFromCaller();
|
|
32382
|
+
let result;
|
|
32383
|
+
try {
|
|
32384
|
+
result = await vm.exec([
|
|
32385
|
+
"/bin/sh",
|
|
32386
|
+
"-lc",
|
|
32387
|
+
[
|
|
32388
|
+
"index=0",
|
|
32389
|
+
"for executable in \"$@\"; do",
|
|
32390
|
+
" if command -v \"$executable\" >/dev/null 2>&1; then",
|
|
32391
|
+
" printf \"%s\\n\" \"$index\"",
|
|
32392
|
+
" fi",
|
|
32393
|
+
" index=$((index + 1))",
|
|
32394
|
+
"done"
|
|
32395
|
+
].join("\n"),
|
|
32396
|
+
"moltnet-capability-probe",
|
|
32397
|
+
...unique
|
|
32398
|
+
], { signal: controller.signal });
|
|
32399
|
+
} catch (error) {
|
|
32400
|
+
if (options.signal?.aborted) throw error;
|
|
32401
|
+
if (timedOut) throw new GuestExecutableProbeError("capability_probe_timeout", `Guest executable capability probe timed out after ${timeoutMs}ms`, { cause: error });
|
|
32402
|
+
throw error;
|
|
32403
|
+
} finally {
|
|
32404
|
+
clearTimeout(timeout);
|
|
32405
|
+
options.signal?.removeEventListener("abort", abortFromCaller);
|
|
32406
|
+
}
|
|
32407
|
+
if (result.exitCode !== 0) {
|
|
32408
|
+
const stderr = result.stderr.trim().slice(-MAX_STDERR_DETAIL_LENGTH);
|
|
32409
|
+
throw new GuestExecutableProbeError("capability_probe_failed", `Guest executable capability probe failed (exit ${result.exitCode})${stderr ? `: ${stderr}` : ""}`);
|
|
32410
|
+
}
|
|
32411
|
+
const availableIndexes = new Set(result.stdout.split("\n").filter(Boolean).map((value) => Number.parseInt(value, 10)).filter((value) => Number.isSafeInteger(value) && value >= 0));
|
|
32412
|
+
return {
|
|
32413
|
+
available: unique.filter((_, index) => availableIndexes.has(index)),
|
|
32414
|
+
unavailable: unique.filter((_, index) => !availableIndexes.has(index))
|
|
32415
|
+
};
|
|
32416
|
+
}
|
|
32417
|
+
//#endregion
|
|
32418
|
+
//#region src/runtime/model-selection.ts
|
|
32419
|
+
var RuntimeProfileModelResolutionError = class extends Error {
|
|
32420
|
+
constructor(message) {
|
|
32421
|
+
super(message);
|
|
32422
|
+
this.name = "RuntimeProfileModelResolutionError";
|
|
32423
|
+
}
|
|
32424
|
+
};
|
|
32425
|
+
/**
|
|
32426
|
+
* Resolve the exact runtime-profile model through Pi's custom-model registry.
|
|
32427
|
+
*
|
|
32428
|
+
* `getModel()` from pi-ai only knows generated built-in models. Runtime
|
|
32429
|
+
* profiles commonly select providers declared in the active Pi directory's
|
|
32430
|
+
* models.json, so an unresolved lookup must fail closed rather than letting
|
|
32431
|
+
* createAgentSession silently choose the default from settings.json.
|
|
32432
|
+
*/
|
|
32433
|
+
function resolveRuntimeProfileModel(piAuthDir, provider, modelId, runtimeProfileId) {
|
|
32434
|
+
const authStorage = AuthStorage.create(join(piAuthDir, "auth.json"));
|
|
32435
|
+
const modelsPath = join(piAuthDir, "models.json");
|
|
32436
|
+
const modelRegistry = ModelRegistry.create(authStorage, modelsPath);
|
|
32437
|
+
const modelHandle = modelRegistry.find(provider, modelId);
|
|
32438
|
+
if (!modelHandle) {
|
|
32439
|
+
const registryError = modelRegistry.getError();
|
|
32440
|
+
const detail = registryError ? ` Registry error: ${registryError}` : "";
|
|
32441
|
+
const alternatives = modelRegistry.getAvailable().slice(0, 8).map((model) => `${model.provider}/${model.id}`);
|
|
32442
|
+
throw new RuntimeProfileModelResolutionError(`${runtimeProfileId ? `Runtime profile "${runtimeProfileId}"` : "Runtime profile"} model "${provider}/${modelId}" was not found in ${modelsPath}; refusing Pi default-model fallback.` + (alternatives.length > 0 ? ` Available models include: ${alternatives.join(", ")}.` : "") + detail);
|
|
32443
|
+
}
|
|
32444
|
+
return {
|
|
32445
|
+
modelHandle,
|
|
32446
|
+
modelRegistry
|
|
32447
|
+
};
|
|
32448
|
+
}
|
|
32449
|
+
//#endregion
|
|
32672
32450
|
//#region src/runtime/resolve-prior-context.ts
|
|
32673
32451
|
/**
|
|
32674
32452
|
* Fetch the named attempt's output and project it into the prompt's
|
|
@@ -32855,6 +32633,40 @@ async function withTimeout(promise, timeoutMs, onTimeout) {
|
|
|
32855
32633
|
}
|
|
32856
32634
|
}
|
|
32857
32635
|
//#endregion
|
|
32636
|
+
//#region src/runtime/runtime-capability-projection.ts
|
|
32637
|
+
/**
|
|
32638
|
+
* Project trusted policy resolution and runtime inventory into the exact
|
|
32639
|
+
* model-visible policy plus host-side degradation diagnostics.
|
|
32640
|
+
*/
|
|
32641
|
+
function projectRuntimeCapabilities(input) {
|
|
32642
|
+
const visibleOptionalTools = input.visibleToolNames.filter((name) => !name.startsWith("submit_"));
|
|
32643
|
+
if (!input.policy) return {
|
|
32644
|
+
instructorPolicy: {
|
|
32645
|
+
enforcement: "off",
|
|
32646
|
+
allowedTools: visibleOptionalTools,
|
|
32647
|
+
allowedShellCommands: [],
|
|
32648
|
+
degraded: false
|
|
32649
|
+
},
|
|
32650
|
+
unavailableTools: [],
|
|
32651
|
+
unavailableExecutables: [],
|
|
32652
|
+
droppedShellCommandCount: 0
|
|
32653
|
+
};
|
|
32654
|
+
const visible = new Set(input.visibleToolNames);
|
|
32655
|
+
const unavailableTools = [...input.policy.allowedTools].filter((name) => !visible.has(name)).sort();
|
|
32656
|
+
const unavailableShellCommands = input.unavailableShellCommands ?? [];
|
|
32657
|
+
return {
|
|
32658
|
+
instructorPolicy: {
|
|
32659
|
+
enforcement: input.policy.enforcement,
|
|
32660
|
+
allowedTools: visibleOptionalTools,
|
|
32661
|
+
allowedShellCommands: input.policy.allowedShellCommands,
|
|
32662
|
+
degraded: input.policy.degraded
|
|
32663
|
+
},
|
|
32664
|
+
unavailableTools,
|
|
32665
|
+
unavailableExecutables: [...new Set(unavailableShellCommands.map(({ argvPrefix }) => argvPrefix[0]))].sort(),
|
|
32666
|
+
droppedShellCommandCount: unavailableShellCommands.length
|
|
32667
|
+
};
|
|
32668
|
+
}
|
|
32669
|
+
//#endregion
|
|
32858
32670
|
//#region src/runtime/runtime-context.ts
|
|
32859
32671
|
/**
|
|
32860
32672
|
* Pi-specific runtime context handling.
|
|
@@ -32979,6 +32791,73 @@ function buildWorkspaceMountInstructions(guestWorkspace) {
|
|
|
32979
32791
|
" non-existent checkout."
|
|
32980
32792
|
].join("\n");
|
|
32981
32793
|
}
|
|
32794
|
+
function buildToolPolicyInstructions(policy) {
|
|
32795
|
+
const lines = [
|
|
32796
|
+
"## Effective runtime tool policy",
|
|
32797
|
+
"",
|
|
32798
|
+
"- The registered submit-output tool is always the completion protocol."
|
|
32799
|
+
];
|
|
32800
|
+
if (!policy || policy.enforcement === "off") {
|
|
32801
|
+
lines.push("- Enforcement is off: runtime policy does not restrict visible tools or", " shell commands. The live sandbox still determines what is installed.");
|
|
32802
|
+
return lines.join("\n");
|
|
32803
|
+
}
|
|
32804
|
+
lines.push(`- Enforcement mode: \`${policy.enforcement}\`.`);
|
|
32805
|
+
if (policy.degraded) lines.push("- Policy resolution degraded. Enforce mode is fail-closed; only the", " kernel submit-output tool is available.");
|
|
32806
|
+
lines.push(policy.allowedTools.length > 0 ? "- The visible structured-tool definitions are the authorized surface." : policy.enforcement === "enforce" ? "- No optional structured tools are authorized." : "- No optional structured tools are registered.");
|
|
32807
|
+
if (policy.enforcement === "watch") lines.push("- Watch mode records policy decisions but does not block tool calls.");
|
|
32808
|
+
else if (policy.allowedShellCommands.length === 0) lines.push("- No shell commands are authorized. `bash` is not available; do not", " attempt shell, filesystem, git, GitHub CLI, or MoltNet CLI commands.");
|
|
32809
|
+
else lines.push("- Shell commands are restricted to these authorized argv prefixes:", ...renderShellCommandPrefixes(policy.allowedShellCommands), "- A visible `bash` tool does not grant broader shell authority. Do not", " attempt commands outside those prefixes.");
|
|
32810
|
+
lines.push("- Tools and commands absent from this effective policy are unavailable,", " even if advisory context mentions them.");
|
|
32811
|
+
return lines.join("\n");
|
|
32812
|
+
}
|
|
32813
|
+
function renderShellCommandPrefixes(commands) {
|
|
32814
|
+
const visible = commands.slice(0, 12).map(({ argvPrefix }) => ` - \`${argvPrefix.join(" ")}\``);
|
|
32815
|
+
const omitted = commands.length - visible.length;
|
|
32816
|
+
if (omitted > 0) visible.push(` - …and ${omitted} more authorized prefixes.`);
|
|
32817
|
+
return visible;
|
|
32818
|
+
}
|
|
32819
|
+
function buildSandboxCapabilityInstructions(sandbox, policy) {
|
|
32820
|
+
if (!sandbox) return "";
|
|
32821
|
+
const executableLines = !policy || policy.enforcement === "off" ? ["- Executables are discovered through the visible shell when needed."] : [sandbox.verifiedExecutables.length > 0 ? `- Session-verified policy executables: ${sandbox.verifiedExecutables.map((name) => `\`${name}\``).join(", ")}.` : "- No policy-relevant guest executables were verified for this session.", ...policy.enforcement === "watch" ? ["- Watch-mode probes are diagnostic, not an executable", " allowlist; other installed commands remain policy-permitted."] : []];
|
|
32822
|
+
const lines = [
|
|
32823
|
+
"## Effective sandbox capabilities",
|
|
32824
|
+
"",
|
|
32825
|
+
`- Workspace mode: \`${sandbox.workspaceMode}\`.`,
|
|
32826
|
+
`- VFS shadow mode: \`${sandbox.vfsShadowMode}\`${sandbox.vfsShadowPatterns.length > 0 ? ` for ${sandbox.vfsShadowPatterns.map((pattern) => `\`${pattern}\``).join(", ")}` : ""}.`,
|
|
32827
|
+
...sandbox.nodeModulesWriteMode ? ["- `node_modules` writes use session-local tmpfs and do not persist", " to the mounted workspace."] : [],
|
|
32828
|
+
...executableLines
|
|
32829
|
+
];
|
|
32830
|
+
const externalHosts = [...sandbox.allowedHosts].sort();
|
|
32831
|
+
const internalHosts = [...sandbox.allowedInternalHosts].sort();
|
|
32832
|
+
lines.push(...externalHosts.length > 0 ? [`- Additional external egress hosts: ${externalHosts.map((host) => `\`${host}\``).join(", ")}.`] : [], ...internalHosts.length > 0 ? [`- Additional internal egress hosts: ${internalHosts.map((host) => `\`${host}\``).join(", ")}.`] : [], "- Runtime service endpoints required for task execution may be available", " in addition to the operator-configured hosts above.");
|
|
32833
|
+
return lines.join("\n");
|
|
32834
|
+
}
|
|
32835
|
+
function shellExecutableIsAvailable(policy, sandbox, executable) {
|
|
32836
|
+
if (!policy || policy.enforcement === "off") return true;
|
|
32837
|
+
if (sandbox && !sandbox.verifiedExecutables.includes(executable)) return false;
|
|
32838
|
+
if (policy.enforcement !== "enforce") return true;
|
|
32839
|
+
return policy.allowedShellCommands.some(({ argvPrefix }) => argvPrefix[0] === executable);
|
|
32840
|
+
}
|
|
32841
|
+
function buildCredentialInstructions(policy, sandbox) {
|
|
32842
|
+
const lines = [
|
|
32843
|
+
"## Identity & credentials",
|
|
32844
|
+
"",
|
|
32845
|
+
"- Your credentials live at `/home/agent/.moltnet/<agent>/moltnet.json`",
|
|
32846
|
+
" with the gitconfig and SSH key alongside. Do not move, copy, or expose",
|
|
32847
|
+
" these files outside the VM."
|
|
32848
|
+
];
|
|
32849
|
+
const moltnetAvailable = shellExecutableIsAvailable(policy, sandbox, "moltnet");
|
|
32850
|
+
const ghAvailable = shellExecutableIsAvailable(policy, sandbox, "gh");
|
|
32851
|
+
const gitAvailable = shellExecutableIsAvailable(policy, sandbox, "git");
|
|
32852
|
+
if (moltnetAvailable) lines.push("- When authorized by the effective shell policy, use the installed", " `moltnet` binary on `PATH`; never invoke a cached or `npx` copy.");
|
|
32853
|
+
if (ghAvailable) {
|
|
32854
|
+
lines.push("- This headless VM has no human GitHub token fallback. Every authorized", " `gh` write must use an inline App token.");
|
|
32855
|
+
if (moltnetAvailable) lines.push("", " ```bash", " CREDS=\"$(cd \"$(dirname \"$GIT_CONFIG_GLOBAL\")\" && pwd)/moltnet.json\"", " GH_TOKEN=$(moltnet github token --credentials \"$CREDS\") gh <command>", " ```");
|
|
32856
|
+
else lines.push("- The effective policy does not authorize the `moltnet` token-minting", " command, so do not attempt a GitHub write.");
|
|
32857
|
+
}
|
|
32858
|
+
if (gitAvailable) lines.push("- An authorized `git push` uses the injected credential helper and does", " not need `GH_TOKEN`.");
|
|
32859
|
+
return lines.join("\n");
|
|
32860
|
+
}
|
|
32982
32861
|
/**
|
|
32983
32862
|
* Build the minimal immutable system-prompt kernel. Runtime-profile context
|
|
32984
32863
|
* carries operator-selected workflow guidance; this kernel stays last in the
|
|
@@ -33001,31 +32880,7 @@ function buildRuntimeKernel(ctx) {
|
|
|
33001
32880
|
`- Diary id (for this task): \`${ctx.diaryId}\``,
|
|
33002
32881
|
`- Agent name: \`${ctx.agentName}\``,
|
|
33003
32882
|
"",
|
|
33004
|
-
|
|
33005
|
-
"",
|
|
33006
|
-
"- Your credentials live at `/home/agent/.moltnet/<agent>/moltnet.json`",
|
|
33007
|
-
" with the gitconfig and SSH key alongside. Do not move, copy, or expose",
|
|
33008
|
-
" these files outside the VM.",
|
|
33009
|
-
"- The `moltnet` CLI is installed in the VM and is the only supported way",
|
|
33010
|
-
" to mint short-lived tokens. Do not invoke `npx @themoltnet/cli` or any",
|
|
33011
|
-
" cached path — use the `moltnet` binary on `PATH`.",
|
|
33012
|
-
"- Interactive sessions use the canonical `moltnet github guard` policy,",
|
|
33013
|
-
" documented in `docs/reference/agent-configuration.md`. This headless VM",
|
|
33014
|
-
" has no editor hook and no human GitHub token to fall back to: read-only",
|
|
33015
|
-
" `gh` commands may run bare, but every write must use the App token:",
|
|
33016
|
-
"",
|
|
33017
|
-
" ```bash",
|
|
33018
|
-
" CREDS=\"$(cd \"$(dirname \"$GIT_CONFIG_GLOBAL\")\" && pwd)/moltnet.json\"",
|
|
33019
|
-
" GH_TOKEN=$(moltnet github token --credentials \"$CREDS\") gh <command>",
|
|
33020
|
-
" ```",
|
|
33021
|
-
"",
|
|
33022
|
-
"- `git push` uses the gitconfig-configured credential helper and is not",
|
|
33023
|
-
" a `gh` call — it does not need `GH_TOKEN`.",
|
|
33024
|
-
"- Run `git` and `gh` in the VM with your normal `bash` tool — your",
|
|
33025
|
-
" credentials are injected here, so they work in the guest. The",
|
|
33026
|
-
" `moltnet_host_exec` tool is a last-resort host escape-hatch that",
|
|
33027
|
-
" requires human approval and is unavailable in headless task runs;",
|
|
33028
|
-
" never use it for routine git/gh.",
|
|
32883
|
+
buildCredentialInstructions(ctx.toolPolicy, ctx.sandbox),
|
|
33029
32884
|
"",
|
|
33030
32885
|
"## Skill packs",
|
|
33031
32886
|
"",
|
|
@@ -33038,6 +32893,10 @@ function buildRuntimeKernel(ctx) {
|
|
|
33038
32893
|
"",
|
|
33039
32894
|
buildWorkspaceMountInstructions(ctx.guestWorkspace),
|
|
33040
32895
|
"",
|
|
32896
|
+
buildSandboxCapabilityInstructions(ctx.sandbox, ctx.toolPolicy),
|
|
32897
|
+
...ctx.sandbox ? [""] : [],
|
|
32898
|
+
buildToolPolicyInstructions(ctx.toolPolicy),
|
|
32899
|
+
"",
|
|
33041
32900
|
"## Structured completion",
|
|
33042
32901
|
"- The registered submit-output tool is the only completion wire protocol. Submit its typed payload when work is complete; prose is not a substitute."
|
|
33043
32902
|
].join("\n");
|
|
@@ -33149,6 +33008,7 @@ function createSubagentTool(args) {
|
|
|
33149
33008
|
cwdPath: args.cwdPath ?? args.mountPath,
|
|
33150
33009
|
piAuthDir: args.piAuthDir,
|
|
33151
33010
|
modelHandle: args.modelHandle,
|
|
33011
|
+
modelRegistry: args.modelRegistry,
|
|
33152
33012
|
thinkingLevel: args.thinkingLevel,
|
|
33153
33013
|
temperature: args.temperature,
|
|
33154
33014
|
topP: args.topP,
|
|
@@ -33276,6 +33136,39 @@ function toolError(text, details = { captured: false }) {
|
|
|
33276
33136
|
};
|
|
33277
33137
|
}
|
|
33278
33138
|
//#endregion
|
|
33139
|
+
//#region src/runtime/submit-completion-coordinator.ts
|
|
33140
|
+
/**
|
|
33141
|
+
* Delay the post-submit session abort until every tool call in Pi's current
|
|
33142
|
+
* parallel batch has emitted `tool_execution_end`. A valid submit call can
|
|
33143
|
+
* finish before a sibling write or artifact upload; aborting immediately would
|
|
33144
|
+
* cancel that sibling after the runtime had already accepted the output.
|
|
33145
|
+
*/
|
|
33146
|
+
function createSubmitCompletionCoordinator(options) {
|
|
33147
|
+
const activeToolCalls = /* @__PURE__ */ new Set();
|
|
33148
|
+
let completionRequested = false;
|
|
33149
|
+
let completionStarted = false;
|
|
33150
|
+
const drain = () => {
|
|
33151
|
+
if (!completionRequested || completionStarted || activeToolCalls.size > 0) return;
|
|
33152
|
+
completionStarted = true;
|
|
33153
|
+
Promise.resolve(options.onDrained()).catch(options.onError);
|
|
33154
|
+
};
|
|
33155
|
+
return {
|
|
33156
|
+
extension: (pi) => {
|
|
33157
|
+
pi.on("tool_execution_start", (event) => {
|
|
33158
|
+
activeToolCalls.add(event.toolCallId);
|
|
33159
|
+
});
|
|
33160
|
+
pi.on("tool_execution_end", (event) => {
|
|
33161
|
+
activeToolCalls.delete(event.toolCallId);
|
|
33162
|
+
drain();
|
|
33163
|
+
});
|
|
33164
|
+
},
|
|
33165
|
+
requestCompletion: () => {
|
|
33166
|
+
completionRequested = true;
|
|
33167
|
+
drain();
|
|
33168
|
+
}
|
|
33169
|
+
};
|
|
33170
|
+
}
|
|
33171
|
+
//#endregion
|
|
33279
33172
|
//#region src/runtime/task-output.ts
|
|
33280
33173
|
var METER_NAME = "@themoltnet/pi-extension/task-output";
|
|
33281
33174
|
var parseResultCounter = null;
|
|
@@ -33445,7 +33338,8 @@ function submitOutputRepairHint(taskType, errors) {
|
|
|
33445
33338
|
const hints = ["Tool args must be the output object directly, not wrapped in { output: ... }."];
|
|
33446
33339
|
if (fields.has("output/artifacts")) hints.push("`artifacts` must be an array; omit it when there are no artifacts, use [], or use objects like { \"kind\": \"note\", \"title\": \"Result\", \"body\": \"...\" }.");
|
|
33447
33340
|
if (fields.has("output/verification")) hints.push("`verification` must be an object with inputCid, results[], and passed; do not send it as text or an array.");
|
|
33448
|
-
if (
|
|
33341
|
+
if (fields.has("output/artifacts") || fields.has("output/verification")) if (taskType === "freeform") hints.push("Minimal valid freeform retry: { \"summary\": \"completed\", \"artifacts\": [], \"verification\": { \"inputCid\": \"<task inputCid>\", \"results\": [{ \"id\": \"submit-output\", \"kind\": \"gate\", \"status\": \"pass\", \"detail\": \"submit_freeform_output accepted valid args\" }], \"passed\": true } }.");
|
|
33342
|
+
else hints.push(`\`verification\` is a stamp when the only gate is submit-output: { "inputCid": "<task inputCid>", "results": [{ "id": "submit-output", "kind": "gate", "status": "pass", "detail": "submit_${taskType}_output accepted valid args" }], "passed": true }.`);
|
|
33449
33343
|
if (hints.length === 1) hints.push("Fix every listed field before re-calling this same tool.");
|
|
33450
33344
|
return hints.join(" ");
|
|
33451
33345
|
}
|
|
@@ -33463,7 +33357,18 @@ function onlySubmitOutputGate(input) {
|
|
|
33463
33357
|
if (Array.isArray(assertions) && assertions.length > 0) return false;
|
|
33464
33358
|
return criteria.rubric === void 0 && criteria.sideEffects === void 0 && criteria.minComposite === void 0;
|
|
33465
33359
|
}
|
|
33466
|
-
|
|
33360
|
+
/**
|
|
33361
|
+
* Repair a producer submit-output payload when the task's ONLY success gate is
|
|
33362
|
+
* the auto-injected submit-output gate — i.e. there is nothing substantive to
|
|
33363
|
+
* self-assess, so the `verification` record is a mechanical stamp. Applies to
|
|
33364
|
+
* any producer task type (freeform, run_eval, …), not just freeform: weaker
|
|
33365
|
+
* models mis-type or omit the nested `verification` object identically across
|
|
33366
|
+
* types, and previously only freeform was repaired, so run_eval attempts failed
|
|
33367
|
+
* `output_validation_failed` on verification alone. The freeform-only field
|
|
33368
|
+
* coercions below are guarded by field presence, so they no-op for other types,
|
|
33369
|
+
* and the caller re-validates the repaired payload against the type's schema.
|
|
33370
|
+
*/
|
|
33371
|
+
function repairProducerSubmitOutput(taskType, params, opts) {
|
|
33467
33372
|
if (!isRecord(params) || !opts.inputCid || !onlySubmitOutputGate(opts.input)) return null;
|
|
33468
33373
|
const repaired = { ...params };
|
|
33469
33374
|
if ("artifacts" in repaired && !Array.isArray(repaired.artifacts)) if (isRecord(repaired.artifacts)) repaired.artifacts = [repaired.artifacts];
|
|
@@ -33479,15 +33384,14 @@ function repairFreeformSubmitOutput(params, opts) {
|
|
|
33479
33384
|
id: SUBMIT_OUTPUT_GATE_ID,
|
|
33480
33385
|
kind: "gate",
|
|
33481
33386
|
status: "pass",
|
|
33482
|
-
detail:
|
|
33387
|
+
detail: `submit_${taskType}_output accepted valid args`
|
|
33483
33388
|
}],
|
|
33484
33389
|
passed: true
|
|
33485
33390
|
};
|
|
33486
33391
|
return repaired;
|
|
33487
33392
|
}
|
|
33488
33393
|
function maybeRepairSubmitOutput(taskType, params, opts) {
|
|
33489
|
-
|
|
33490
|
-
const repaired = repairFreeformSubmitOutput(params, opts);
|
|
33394
|
+
const repaired = repairProducerSubmitOutput(taskType, params, opts);
|
|
33491
33395
|
if (!repaired) return null;
|
|
33492
33396
|
return validateTaskSubmission(taskType, repaired, opts.input, { inputCid: opts.inputCid }).length === 0 ? repaired : null;
|
|
33493
33397
|
}
|
|
@@ -33511,10 +33415,24 @@ Agent submission schema:\n\`\`\`json\n${contract.parametersSchemaJson}\n\`\`\``,
|
|
|
33511
33415
|
promptGuidelines: [
|
|
33512
33416
|
`Call \`${contract.toolName}\` with the exact ${taskType} agent submission shape shown above.`,
|
|
33513
33417
|
"The transport accepts malformed objects only so validation errors can be recovered in-session; the schema shown above is authoritative.",
|
|
33514
|
-
"If the submit tool returns a validation error, fix every listed field and call the same tool again."
|
|
33418
|
+
"If the submit tool returns a validation error, fix every listed field and call the same tool again.",
|
|
33419
|
+
"The first valid submission is final and immediately ends the session."
|
|
33515
33420
|
],
|
|
33516
33421
|
parameters: RecoverableSubmitToolParameters,
|
|
33517
33422
|
async execute(_id, params) {
|
|
33423
|
+
if (captured) return {
|
|
33424
|
+
content: [{
|
|
33425
|
+
type: "text",
|
|
33426
|
+
text: "Output was already captured. The first valid payload remains final; this duplicate submission was ignored."
|
|
33427
|
+
}],
|
|
33428
|
+
details: {
|
|
33429
|
+
captured: true,
|
|
33430
|
+
callCount,
|
|
33431
|
+
invalidCallCount,
|
|
33432
|
+
maxSubmitValidationRetries,
|
|
33433
|
+
error: null
|
|
33434
|
+
}
|
|
33435
|
+
};
|
|
33518
33436
|
if (exhaustedValidationFailure) return {
|
|
33519
33437
|
content: [{
|
|
33520
33438
|
type: "text",
|
|
@@ -33565,6 +33483,7 @@ Agent submission schema:\n\`\`\`json\n${contract.parametersSchemaJson}\n\`\`\``,
|
|
|
33565
33483
|
}
|
|
33566
33484
|
captured = candidateParams;
|
|
33567
33485
|
callCount += 1;
|
|
33486
|
+
await opts.onValidCapture?.();
|
|
33568
33487
|
return {
|
|
33569
33488
|
content: [{
|
|
33570
33489
|
type: "text",
|
|
@@ -34005,7 +33924,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34005
33924
|
let subagentHandle = null;
|
|
34006
33925
|
const finalUsage = emptyUsage(opts.provider, opts.model);
|
|
34007
33926
|
let cancelListener = null;
|
|
34008
|
-
const makeFailedOutput = (code, message, usage = finalUsage) => ({
|
|
33927
|
+
const makeFailedOutput = (code, message, usage = finalUsage, retryable = false) => ({
|
|
34009
33928
|
taskId: task.id,
|
|
34010
33929
|
attemptN,
|
|
34011
33930
|
status: "failed",
|
|
@@ -34016,7 +33935,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34016
33935
|
error: {
|
|
34017
33936
|
code,
|
|
34018
33937
|
message,
|
|
34019
|
-
retryable
|
|
33938
|
+
retryable
|
|
34020
33939
|
}
|
|
34021
33940
|
});
|
|
34022
33941
|
const makeCancelledOutput = (message) => ({
|
|
@@ -34069,6 +33988,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34069
33988
|
reporterOpen = true;
|
|
34070
33989
|
let checkpointPath;
|
|
34071
33990
|
let resolvedVmTemplate = opts.resolvedVmTemplate;
|
|
33991
|
+
let effectiveSandboxConfig;
|
|
34072
33992
|
try {
|
|
34073
33993
|
if (!resolvedVmTemplate && opts.runtimeDefinition) resolvedVmTemplate = opts.resolveVmTemplate ? await opts.resolveVmTemplate() : await opts.runtimeDefinition.vm.resolve({ onProgress: opts.onSnapshotProgress });
|
|
34074
33994
|
checkpointPath = resolvedVmTemplate?.checkpointPath ?? opts.checkpointPath ?? (opts.resolveCheckpointPath ? await opts.resolveCheckpointPath() : await ensureSnapshot({
|
|
@@ -34092,7 +34012,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34092
34012
|
return makeFailedOutput("worktree_setup_failed", message);
|
|
34093
34013
|
}
|
|
34094
34014
|
try {
|
|
34095
|
-
|
|
34015
|
+
effectiveSandboxConfig = applyExecutionPlanSandboxOverrides(resolvedVmTemplate ? {
|
|
34096
34016
|
...opts.sandboxConfig,
|
|
34097
34017
|
snapshot: void 0,
|
|
34098
34018
|
resumeCommands: [...resolvedVmTemplate.resumeCommands]
|
|
@@ -34104,7 +34024,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34104
34024
|
mountPath,
|
|
34105
34025
|
workspaceMode: workspace.mode,
|
|
34106
34026
|
extraAllowedHosts: opts.extraAllowedHosts,
|
|
34107
|
-
sandboxConfig,
|
|
34027
|
+
sandboxConfig: effectiveSandboxConfig,
|
|
34108
34028
|
forwardEnv: opts.forwardEnv,
|
|
34109
34029
|
signal: reporter.cancelSignal
|
|
34110
34030
|
});
|
|
@@ -34234,11 +34154,20 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34234
34154
|
cwdPath,
|
|
34235
34155
|
guestWorkspace: managed.guestWorkspace
|
|
34236
34156
|
});
|
|
34157
|
+
const submitCompletion = createSubmitCompletionCoordinator({
|
|
34158
|
+
onDrained: () => session?.abort(),
|
|
34159
|
+
onError: async (err) => {
|
|
34160
|
+
await emitError("submit_output_abort", err instanceof Error ? err.message : String(err), { event: "submit_output_abort_failed" });
|
|
34161
|
+
}
|
|
34162
|
+
});
|
|
34237
34163
|
const { handle: submitToolHandle, tools: submitToolDefs } = resolveSubmitTools(task.taskType, {
|
|
34238
34164
|
model: opts.model,
|
|
34239
34165
|
input: task.input,
|
|
34240
34166
|
inputCid: task.inputCid,
|
|
34241
|
-
maxSubmitValidationRetries: opts.maxSubmitValidationRetries
|
|
34167
|
+
maxSubmitValidationRetries: opts.maxSubmitValidationRetries,
|
|
34168
|
+
onValidCapture: () => {
|
|
34169
|
+
submitCompletion.requestCompletion();
|
|
34170
|
+
}
|
|
34242
34171
|
});
|
|
34243
34172
|
const submitTools = submitToolDefs;
|
|
34244
34173
|
try {
|
|
@@ -34266,48 +34195,45 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34266
34195
|
correlationId: task.correlationId ?? null
|
|
34267
34196
|
})
|
|
34268
34197
|
});
|
|
34269
|
-
const piAuthDir =
|
|
34270
|
-
const modelHandle =
|
|
34271
|
-
const runtimeKernel = buildRuntimeKernel({
|
|
34272
|
-
taskId: task.id,
|
|
34273
|
-
taskType: task.taskType,
|
|
34274
|
-
attemptN,
|
|
34275
|
-
diaryId,
|
|
34276
|
-
agentName: opts.agentName,
|
|
34277
|
-
guestWorkspace: managed.guestWorkspace,
|
|
34278
|
-
correlationId: task.correlationId ?? null
|
|
34279
|
-
});
|
|
34280
|
-
const appendSystemPrompt = composeRuntimeSystemPrompt({
|
|
34281
|
-
profilePromptPrefix: injectedContext.systemPromptPrefix,
|
|
34282
|
-
kernel: runtimeKernel
|
|
34283
|
-
});
|
|
34198
|
+
const piAuthDir = resolvePiCodingAgentDir();
|
|
34199
|
+
const { modelHandle, modelRegistry } = resolveRuntimeProfileModel(piAuthDir, opts.provider, opts.model, opts.runtimeProfileId);
|
|
34284
34200
|
const injectedSkills = injectedContext.skills;
|
|
34285
34201
|
const toolPolicyExtensions = [];
|
|
34286
34202
|
let resolvedToolPolicy;
|
|
34203
|
+
let unavailableRuntimeShellCommands = [];
|
|
34204
|
+
let verifiedGuestExecutables = [];
|
|
34205
|
+
const toolPolicyLogger = opts.toolPolicyLogger ?? {
|
|
34206
|
+
debug: () => {},
|
|
34207
|
+
info: (obj, msg) => console.error(JSON.stringify({
|
|
34208
|
+
level: "info",
|
|
34209
|
+
msg,
|
|
34210
|
+
...obj
|
|
34211
|
+
})),
|
|
34212
|
+
warn: (obj, msg) => console.error(JSON.stringify({
|
|
34213
|
+
level: "warn",
|
|
34214
|
+
msg,
|
|
34215
|
+
...obj
|
|
34216
|
+
}))
|
|
34217
|
+
};
|
|
34287
34218
|
if (opts.runtimeProfileId && opts.toolEnforcement && opts.toolEnforcement !== "off") {
|
|
34288
|
-
const toolPolicyLogger = opts.toolPolicyLogger ?? {
|
|
34289
|
-
debug: () => {},
|
|
34290
|
-
info: (obj, msg) => console.error(JSON.stringify({
|
|
34291
|
-
level: "info",
|
|
34292
|
-
msg,
|
|
34293
|
-
...obj
|
|
34294
|
-
})),
|
|
34295
|
-
warn: (obj, msg) => console.error(JSON.stringify({
|
|
34296
|
-
level: "warn",
|
|
34297
|
-
msg,
|
|
34298
|
-
...obj
|
|
34299
|
-
}))
|
|
34300
|
-
};
|
|
34301
34219
|
const [analyzer, policy] = await Promise.all([ShellCommandAnalyzer.create(), resolveSessionToolPolicy({
|
|
34302
34220
|
agent: moltnetAgent,
|
|
34303
34221
|
profileId: opts.runtimeProfileId,
|
|
34304
34222
|
teamId: taskTeamId,
|
|
34223
|
+
runtimeKind: opts.runtimeDefinition?.runtimeKind ?? "gondolin_pi",
|
|
34305
34224
|
enforcement: opts.toolEnforcement,
|
|
34306
34225
|
logger: toolPolicyLogger
|
|
34307
34226
|
})]);
|
|
34308
|
-
|
|
34227
|
+
verifiedGuestExecutables = (await discoverGuestExecutables(managed.vm, [...policy.allowedShellCommands.map(({ argvPrefix }) => argvPrefix[0]), ...policy.enforcement === "watch" ? resolvedVmTemplate?.executables ?? [] : []], { signal: reporter.cancelSignal })).available;
|
|
34228
|
+
const availableExecutables = new Set(verifiedGuestExecutables);
|
|
34229
|
+
const allowedShellCommands = policy.allowedShellCommands.filter(({ argvPrefix }) => availableExecutables.has(argvPrefix[0]));
|
|
34230
|
+
unavailableRuntimeShellCommands = policy.allowedShellCommands.filter(({ argvPrefix }) => !availableExecutables.has(argvPrefix[0]));
|
|
34231
|
+
resolvedToolPolicy = {
|
|
34232
|
+
...policy,
|
|
34233
|
+
allowedShellCommands
|
|
34234
|
+
};
|
|
34309
34235
|
toolPolicyExtensions.push(createToolPolicyExtension({
|
|
34310
|
-
policy,
|
|
34236
|
+
policy: resolvedToolPolicy,
|
|
34311
34237
|
analyzer,
|
|
34312
34238
|
logger: toolPolicyLogger
|
|
34313
34239
|
}));
|
|
@@ -34345,13 +34271,67 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34345
34271
|
policy: resolvedToolPolicy
|
|
34346
34272
|
}) : [];
|
|
34347
34273
|
const visibleBaseTools = filterModelVisibleTools([...gondolinCustomTools, ...moltnetTools], resolvedToolPolicy);
|
|
34274
|
+
const taskHasSubagents = taskTypeUsesSubagents(task.taskType);
|
|
34275
|
+
const visibleParentToolNames = modelVisiblePiToolNames({
|
|
34276
|
+
tools: [
|
|
34277
|
+
...visibleBaseTools,
|
|
34278
|
+
...runtimeParentTools,
|
|
34279
|
+
...submitTools,
|
|
34280
|
+
...taskHasSubagents ? [{ name: "subagent" }] : []
|
|
34281
|
+
],
|
|
34282
|
+
extensions: opts.runtimeDefinition?.extensions,
|
|
34283
|
+
policy: resolvedToolPolicy
|
|
34284
|
+
});
|
|
34285
|
+
const capabilityProjection = projectRuntimeCapabilities({
|
|
34286
|
+
policy: resolvedToolPolicy,
|
|
34287
|
+
visibleToolNames: visibleParentToolNames,
|
|
34288
|
+
unavailableShellCommands: unavailableRuntimeShellCommands
|
|
34289
|
+
});
|
|
34290
|
+
if (capabilityProjection.unavailableTools.length > 0 || capabilityProjection.unavailableExecutables.length > 0) {
|
|
34291
|
+
const diagnostics = {
|
|
34292
|
+
runtimeProfileId: opts.runtimeProfileId,
|
|
34293
|
+
unavailableTools: capabilityProjection.unavailableTools,
|
|
34294
|
+
unavailableExecutables: capabilityProjection.unavailableExecutables,
|
|
34295
|
+
droppedShellCommandCount: capabilityProjection.droppedShellCommandCount
|
|
34296
|
+
};
|
|
34297
|
+
toolPolicyLogger.warn(diagnostics, "Runtime policy grants unavailable capabilities");
|
|
34298
|
+
await emit("info", {
|
|
34299
|
+
event: "runtime_capabilities_unavailable",
|
|
34300
|
+
...diagnostics
|
|
34301
|
+
});
|
|
34302
|
+
}
|
|
34303
|
+
const vfsShadow = resolveVfsShadowConfig(effectiveSandboxConfig);
|
|
34304
|
+
const runtimeKernel = buildRuntimeKernel({
|
|
34305
|
+
taskId: task.id,
|
|
34306
|
+
taskType: task.taskType,
|
|
34307
|
+
attemptN,
|
|
34308
|
+
diaryId,
|
|
34309
|
+
agentName: opts.agentName,
|
|
34310
|
+
guestWorkspace: managed.guestWorkspace,
|
|
34311
|
+
correlationId: task.correlationId ?? null,
|
|
34312
|
+
sandbox: {
|
|
34313
|
+
workspaceMode: activeWorkspace.mode,
|
|
34314
|
+
vfsShadowMode: vfsShadow.mode,
|
|
34315
|
+
vfsShadowPatterns: vfsShadow.patterns,
|
|
34316
|
+
nodeModulesWriteMode: "tmpfs",
|
|
34317
|
+
verifiedExecutables: verifiedGuestExecutables,
|
|
34318
|
+
allowedHosts: [...effectiveSandboxConfig?.network?.allowedHosts ?? [], ...opts.extraAllowedHosts ?? []],
|
|
34319
|
+
allowedInternalHosts: effectiveSandboxConfig?.network?.allowedInternalHosts ?? []
|
|
34320
|
+
},
|
|
34321
|
+
toolPolicy: capabilityProjection.instructorPolicy
|
|
34322
|
+
});
|
|
34323
|
+
const appendSystemPrompt = composeRuntimeSystemPrompt({
|
|
34324
|
+
profilePromptPrefix: injectedContext.systemPromptPrefix,
|
|
34325
|
+
kernel: runtimeKernel
|
|
34326
|
+
});
|
|
34348
34327
|
const parentSubagentTools = [];
|
|
34349
|
-
if (
|
|
34328
|
+
if (taskHasSubagents) {
|
|
34350
34329
|
subagentHandle = createSubagentTool({
|
|
34351
34330
|
mountPath,
|
|
34352
34331
|
cwdPath,
|
|
34353
34332
|
piAuthDir,
|
|
34354
34333
|
modelHandle,
|
|
34334
|
+
modelRegistry,
|
|
34355
34335
|
thinkingLevel: opts.thinkingLevel,
|
|
34356
34336
|
temperature: opts.temperature,
|
|
34357
34337
|
topP: opts.topP,
|
|
@@ -34385,6 +34365,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34385
34365
|
cwdPath,
|
|
34386
34366
|
piAuthDir,
|
|
34387
34367
|
modelHandle,
|
|
34368
|
+
modelRegistry,
|
|
34388
34369
|
thinkingLevel: opts.thinkingLevel,
|
|
34389
34370
|
temperature: opts.temperature,
|
|
34390
34371
|
topP: opts.topP,
|
|
@@ -34408,7 +34389,11 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34408
34389
|
"moltnet.task.type": task.taskType
|
|
34409
34390
|
},
|
|
34410
34391
|
sessionPersistence: executionPlan?.sessionPersistence ?? void 0,
|
|
34411
|
-
extraExtensionFactories: [
|
|
34392
|
+
extraExtensionFactories: [
|
|
34393
|
+
...runtimeParentExtensions,
|
|
34394
|
+
...toolPolicyExtensions,
|
|
34395
|
+
submitCompletion.extension
|
|
34396
|
+
]
|
|
34412
34397
|
});
|
|
34413
34398
|
} catch (err) {
|
|
34414
34399
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -34416,6 +34401,9 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
34416
34401
|
message,
|
|
34417
34402
|
phase: "session_setup"
|
|
34418
34403
|
});
|
|
34404
|
+
if (reporter.cancelSignal.aborted) return makeCancelledOutput(reporter.cancelReason ?? "Task cancelled during session setup.");
|
|
34405
|
+
if (err instanceof RuntimeProfileModelResolutionError) return makeFailedOutput("invalid_model", message);
|
|
34406
|
+
if (err instanceof GuestExecutableProbeError) return makeFailedOutput(err.code, message, finalUsage, true);
|
|
34419
34407
|
return makeFailedOutput("session_setup_failed", message);
|
|
34420
34408
|
}
|
|
34421
34409
|
const turnState = createSessionTurnState();
|
|
@@ -35249,4 +35237,4 @@ function describeToolErrorMessage(result) {
|
|
|
35249
35237
|
}
|
|
35250
35238
|
}
|
|
35251
35239
|
//#endregion
|
|
35252
|
-
export { GONDOLIN_TOOL_NAMES, HOST_EXEC_DEFAULT_BASE_ENV, MOLTNET_TOOL_NAMES, PI_EXECUTOR_MANIFEST_VERSION, PI_RUNTIME_DEFINITION_VERSION, activateAgentEnv, buildAgentSession, buildPiExecutorManifest, buildRuntimeKernel, buildWorkspaceMountInstructions, createGondolinBashOps, createGondolinEditOps, createGondolinFindOps, createGondolinLsOps, createGondolinReadOps, createGondolinToolDefinitions, createGondolinWriteOps, createMoltNetTools, createPiOtelExtension, createPiRetryTriage, createPiTaskExecutor, createSubagentTool, createToolPolicyExtension, decideForEvent, decideToolCall, defineGondolinTemplate, definePiExtension, definePiRuntime, definePiTool, enabledPiToolNames, ensureSnapshot, executeGondolinGrep, executePiTask, filterModelVisibleTools, findMainWorktree, injectRuntimeContext as injectTaskContext, isKernelTool, isToolVisible, loadCredentials, materializePiExtensions, materializePiTools, normalizeRetryTriageResult, redactRetryTriageSecrets, resolveSessionToolPolicy, resolveTaskWorktreePath, resumeVm, toGuestPath };
|
|
35240
|
+
export { GONDOLIN_TOOL_NAMES, HOST_EXEC_DEFAULT_BASE_ENV, MOLTNET_TOOL_NAMES, PI_EXECUTOR_MANIFEST_VERSION, PI_RUNTIME_DEFINITION_VERSION, activateAgentEnv, buildAgentSession, buildPiExecutorManifest, buildRuntimeKernel, buildWorkspaceMountInstructions, createGondolinBashOps, createGondolinEditOps, createGondolinFindOps, createGondolinLsOps, createGondolinReadOps, createGondolinToolDefinitions, createGondolinWriteOps, createMoltNetTools, createPiOtelExtension, createPiRetryTriage, createPiTaskExecutor, createSubagentTool, createToolPolicyExtension, decideForEvent, decideToolCall, defineGondolinTemplate, definePiExtension, definePiRuntime, definePiTool, enabledPiToolNames, ensureSnapshot, executeGondolinGrep, executePiTask, filterModelVisibleTools, findMainWorktree, injectRuntimeContext as injectTaskContext, isKernelTool, isResolvedPathInsideRoot, isToolVisible, loadCredentials, materializePiExtensions, materializePiTools, normalizeRetryTriageResult, redactRetryTriageSecrets, resolveSessionToolPolicy, resolveTaskWorktreePath, resumeVm, toGuestPath };
|