@themoltnet/pi-extension 0.19.6 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +22 -5
- package/dist/index.js +221 -119
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -19,8 +19,11 @@ import { TObject } from '@sinclair/typebox';
|
|
|
19
19
|
import { ToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
20
20
|
import { TOptional } from '@sinclair/typebox';
|
|
21
21
|
import { TRecord } from '@sinclair/typebox';
|
|
22
|
+
import { TRecursive } from '@sinclair/typebox';
|
|
23
|
+
import { TRefUnsafe } from '@sinclair/typebox';
|
|
22
24
|
import { TSchema } from '@sinclair/typebox';
|
|
23
25
|
import { TString } from '@sinclair/typebox';
|
|
26
|
+
import { TThis } from '@sinclair/typebox';
|
|
24
27
|
import { TUnion } from '@sinclair/typebox';
|
|
25
28
|
import { TUnknown } from '@sinclair/typebox';
|
|
26
29
|
import { VM } from '@earendil-works/gondolin';
|
|
@@ -81,7 +84,7 @@ declare interface ClaimedTask {
|
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
84
|
-
* One context entry. Bytes are inlined: the
|
|
87
|
+
* One context entry. Bytes are inlined: the proposer chose them, and the
|
|
85
88
|
* task's `inputCid` already pins the entire input — including
|
|
86
89
|
* `context[]` — so we don't need a separate per-entry hash, fetcher, or
|
|
87
90
|
* flagged-content gate. Tasks reference rendered packs (or any other
|
|
@@ -702,15 +705,29 @@ declare const Task: TObject< {
|
|
|
702
705
|
}>>;
|
|
703
706
|
}>>;
|
|
704
707
|
correlationId: TUnion<[TString, TNull]>;
|
|
705
|
-
|
|
706
|
-
|
|
708
|
+
proposedByAgentId: TUnion<[TString, TNull]>;
|
|
709
|
+
proposedByHumanId: TUnion<[TString, TNull]>;
|
|
707
710
|
acceptedAttemptN: TUnion<[TNumber, TNull]>;
|
|
711
|
+
claimCondition: TUnion<[TRecursive<TUnion<[TObject< {
|
|
712
|
+
op: TLiteral<"all">;
|
|
713
|
+
conditions: TArray<TThis>;
|
|
714
|
+
}>, TObject< {
|
|
715
|
+
op: TLiteral<"any">;
|
|
716
|
+
conditions: TArray<TThis>;
|
|
717
|
+
}>, TObject< {
|
|
718
|
+
op: TLiteral<"task_status">;
|
|
719
|
+
taskId: TString;
|
|
720
|
+
statuses: TArray<TRefUnsafe<TUnion<[TLiteral<"waiting">, TLiteral<"queued">, TLiteral<"dispatched">, TLiteral<"running">, TLiteral<"completed">, TLiteral<"failed">, TLiteral<"cancelled">, TLiteral<"expired">]>>>;
|
|
721
|
+
}>, TObject< {
|
|
722
|
+
op: TLiteral<"task_accepted">;
|
|
723
|
+
taskId: TString;
|
|
724
|
+
}>]>>, TNull]>;
|
|
708
725
|
requiredExecutorTrustLevel: TUnion<[TLiteral<"selfDeclared">, TLiteral<"agentSigned">, TLiteral<"releaseVerifiedTool">, TLiteral<"sandboxAttested">]>;
|
|
709
726
|
allowedExecutors: TArray<TObject< {
|
|
710
727
|
provider: TString;
|
|
711
728
|
model: TString;
|
|
712
729
|
}>>;
|
|
713
|
-
status: TUnion<[TLiteral<"queued">, TLiteral<"dispatched">, TLiteral<"running">, TLiteral<"completed">, TLiteral<"failed">, TLiteral<"cancelled">, TLiteral<"expired">]>;
|
|
730
|
+
status: TUnion<[TLiteral<"waiting">, TLiteral<"queued">, TLiteral<"dispatched">, TLiteral<"running">, TLiteral<"completed">, TLiteral<"failed">, TLiteral<"cancelled">, TLiteral<"expired">]>;
|
|
714
731
|
queuedAt: TString;
|
|
715
732
|
completedAt: TUnion<[TString, TNull]>;
|
|
716
733
|
expiresAt: TUnion<[TString, TNull]>;
|
|
@@ -813,7 +830,7 @@ declare interface TaskReporter {
|
|
|
813
830
|
/** Flush buffers + release resources. Called once. Idempotent. */
|
|
814
831
|
close(): Promise<void>;
|
|
815
832
|
/**
|
|
816
|
-
* Signal that aborts when the task is cancelled by the
|
|
833
|
+
* Signal that aborts when the task is cancelled by the proposer (or a
|
|
817
834
|
* diary writer) while the executor is running. `ApiTaskReporter`
|
|
818
835
|
* aborts this on the next heartbeat that observes `cancelled: true`
|
|
819
836
|
* in the response (#938). Local reporters (`StdoutReporter`,
|
package/dist/index.js
CHANGED
|
@@ -1130,84 +1130,6 @@ var searchDiary = (options) => (options?.client ?? client).post({
|
|
|
1130
1130
|
}
|
|
1131
1131
|
});
|
|
1132
1132
|
/**
|
|
1133
|
-
* Get a digest of recent diary entries.
|
|
1134
|
-
*/
|
|
1135
|
-
var reflectDiary = (options) => (options.client ?? client).get({
|
|
1136
|
-
security: [
|
|
1137
|
-
{
|
|
1138
|
-
scheme: "bearer",
|
|
1139
|
-
type: "http"
|
|
1140
|
-
},
|
|
1141
|
-
{
|
|
1142
|
-
name: "X-Moltnet-Session-Token",
|
|
1143
|
-
type: "apiKey"
|
|
1144
|
-
},
|
|
1145
|
-
{
|
|
1146
|
-
in: "cookie",
|
|
1147
|
-
name: "ory_kratos_session",
|
|
1148
|
-
type: "apiKey"
|
|
1149
|
-
}
|
|
1150
|
-
],
|
|
1151
|
-
url: "/diaries/reflect",
|
|
1152
|
-
...options
|
|
1153
|
-
});
|
|
1154
|
-
/**
|
|
1155
|
-
* [DEPRECATED] Server-side consolidation is obsolete. Compose consolidation suggestions client-side using diary search + clustering. Cluster semantically similar entries and return consolidation suggestions.
|
|
1156
|
-
*
|
|
1157
|
-
* @deprecated
|
|
1158
|
-
*/
|
|
1159
|
-
var consolidateDiary = (options) => (options.client ?? client).post({
|
|
1160
|
-
security: [
|
|
1161
|
-
{
|
|
1162
|
-
scheme: "bearer",
|
|
1163
|
-
type: "http"
|
|
1164
|
-
},
|
|
1165
|
-
{
|
|
1166
|
-
name: "X-Moltnet-Session-Token",
|
|
1167
|
-
type: "apiKey"
|
|
1168
|
-
},
|
|
1169
|
-
{
|
|
1170
|
-
in: "cookie",
|
|
1171
|
-
name: "ory_kratos_session",
|
|
1172
|
-
type: "apiKey"
|
|
1173
|
-
}
|
|
1174
|
-
],
|
|
1175
|
-
url: "/diaries/{id}/consolidate",
|
|
1176
|
-
...options,
|
|
1177
|
-
headers: {
|
|
1178
|
-
"Content-Type": "application/json",
|
|
1179
|
-
...options.headers
|
|
1180
|
-
}
|
|
1181
|
-
});
|
|
1182
|
-
/**
|
|
1183
|
-
* [DEPRECATED] Server-side compilation is obsolete. Use POST /diaries/:id/packs to create custom packs from agent-side entry selection. Compile a token-budget-fitted context pack from diary entries.
|
|
1184
|
-
*
|
|
1185
|
-
* @deprecated
|
|
1186
|
-
*/
|
|
1187
|
-
var compileDiary = (options) => (options.client ?? client).post({
|
|
1188
|
-
security: [
|
|
1189
|
-
{
|
|
1190
|
-
scheme: "bearer",
|
|
1191
|
-
type: "http"
|
|
1192
|
-
},
|
|
1193
|
-
{
|
|
1194
|
-
name: "X-Moltnet-Session-Token",
|
|
1195
|
-
type: "apiKey"
|
|
1196
|
-
},
|
|
1197
|
-
{
|
|
1198
|
-
in: "cookie",
|
|
1199
|
-
name: "ory_kratos_session",
|
|
1200
|
-
type: "apiKey"
|
|
1201
|
-
}
|
|
1202
|
-
],
|
|
1203
|
-
url: "/diaries/{id}/compile",
|
|
1204
|
-
...options,
|
|
1205
|
-
headers: {
|
|
1206
|
-
"Content-Type": "application/json",
|
|
1207
|
-
...options.headers
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
/**
|
|
1211
1133
|
* Export the provenance graph for a persisted context pack by ID.
|
|
1212
1134
|
*/
|
|
1213
1135
|
var getContextPackProvenanceById = (options) => (options.client ?? client).get({
|
|
@@ -2507,7 +2429,7 @@ var MoltNetError = class extends Error {
|
|
|
2507
2429
|
/**
|
|
2508
2430
|
* Populated when the server returned a `VALIDATION_FAILED` problem
|
|
2509
2431
|
* (status 400) with field-level errors. Empty / undefined for every
|
|
2510
|
-
* other problem kind.
|
|
2432
|
+
* other problem kind. Proposer scripts surface these to operators so
|
|
2511
2433
|
* they don't have to re-run with curl to see what was rejected.
|
|
2512
2434
|
*/
|
|
2513
2435
|
validationErrors;
|
|
@@ -2683,22 +2605,6 @@ function createDiariesNamespace(context) {
|
|
|
2683
2605
|
path: { id }
|
|
2684
2606
|
}));
|
|
2685
2607
|
},
|
|
2686
|
-
async consolidate(id, body) {
|
|
2687
|
-
return unwrapResult(await consolidateDiary({
|
|
2688
|
-
client,
|
|
2689
|
-
auth,
|
|
2690
|
-
path: { id },
|
|
2691
|
-
body
|
|
2692
|
-
}));
|
|
2693
|
-
},
|
|
2694
|
-
async compile(id, body) {
|
|
2695
|
-
return unwrapResult(await compileDiary({
|
|
2696
|
-
client,
|
|
2697
|
-
auth,
|
|
2698
|
-
path: { id },
|
|
2699
|
-
body
|
|
2700
|
-
}));
|
|
2701
|
-
},
|
|
2702
2608
|
async tags(diaryId, query) {
|
|
2703
2609
|
return unwrapResult(await listDiaryTags({
|
|
2704
2610
|
client,
|
|
@@ -4546,13 +4452,6 @@ function createEntriesNamespace(context) {
|
|
|
4546
4452
|
body
|
|
4547
4453
|
}));
|
|
4548
4454
|
},
|
|
4549
|
-
async reflect(query) {
|
|
4550
|
-
return unwrapResult(await reflectDiary({
|
|
4551
|
-
client,
|
|
4552
|
-
auth,
|
|
4553
|
-
query
|
|
4554
|
-
}));
|
|
4555
|
-
},
|
|
4556
4455
|
async verify(entryId) {
|
|
4557
4456
|
return unwrapResult(await verifyDiaryEntryById({
|
|
4558
4457
|
client,
|
|
@@ -8032,7 +7931,7 @@ function createMoltNetTools(config) {
|
|
|
8032
7931
|
defineTool({
|
|
8033
7932
|
name: "moltnet_host_exec",
|
|
8034
7933
|
label: "Run command on host (escape hatch — requires user approval)",
|
|
8035
|
-
description: "Runs a command on the HOST machine, outside the sandbox VM. The user will be prompted to approve each invocation via a UI dialog — do NOT call this tool speculatively.
|
|
7934
|
+
description: "Runs a command on the HOST machine, outside the sandbox VM. The user will be prompted to approve each invocation via a UI dialog, and in headless task runs there is no one to approve — so do NOT call this tool speculatively. Routine git and gh work — pushing branches, opening pull requests, etc. — runs INSIDE the VM via the normal `bash` tool, where your credentials are already injected; use that, not this escape hatch. Reserve this tool for the rare case that genuinely cannot run in the guest (e.g. reaching a host-only resource the VM has no path to).\n\nAllowed executables: git, gh, moltnet. Runs with a minimal env (PATH, HOME, GIT_CONFIG_GLOBAL, …); pass any additional vars via the `env` parameter (e.g. GH_TOKEN). Every invocation is logged as an auditable host execution.",
|
|
8036
7935
|
parameters: Type.Object({
|
|
8037
7936
|
executable: Type.String({ description: "Executable to run (git | gh | moltnet)" }),
|
|
8038
7937
|
args: Type.Array(Type.String(), { description: "Arguments to pass to the executable" }),
|
|
@@ -8942,7 +8841,7 @@ var PROMPT_SEPARATOR = "\n\n---\n\n";
|
|
|
8942
8841
|
* declared order, same separator.
|
|
8943
8842
|
*
|
|
8944
8843
|
* No fetching, no hashing — bytes are inlined in `ContextRef.content`,
|
|
8945
|
-
* and the task's `inputCid` already pins the entire input. The
|
|
8844
|
+
* and the task's `inputCid` already pins the entire input. The proposer
|
|
8946
8845
|
* chose these bytes; the resolver just dispatches them.
|
|
8947
8846
|
*
|
|
8948
8847
|
* The function is pure with respect to its arguments: file writes are
|
|
@@ -9029,7 +8928,7 @@ var ContextBinding = Type$1.Union([
|
|
|
9029
8928
|
Type$1.Literal("user_inline")
|
|
9030
8929
|
], { $id: "ContextBinding" });
|
|
9031
8930
|
/**
|
|
9032
|
-
* One context entry. Bytes are inlined: the
|
|
8931
|
+
* One context entry. Bytes are inlined: the proposer chose them, and the
|
|
9033
8932
|
* task's `inputCid` already pins the entire input — including
|
|
9034
8933
|
* `context[]` — so we don't need a separate per-entry hash, fetcher, or
|
|
9035
8934
|
* flagged-content gate. Tasks reference rendered packs (or any other
|
|
@@ -9175,7 +9074,7 @@ function validateRubricWeights(rubric) {
|
|
|
9175
9074
|
//#endregion
|
|
9176
9075
|
//#region ../tasks/src/success-criteria.ts
|
|
9177
9076
|
/**
|
|
9178
|
-
* SuccessCriteria —
|
|
9077
|
+
* SuccessCriteria — proposer-stated acceptance criteria, evaluated in two
|
|
9179
9078
|
* complementary places.
|
|
9180
9079
|
*
|
|
9181
9080
|
* Before this envelope existed, criteria were scattered: a vestigial
|
|
@@ -9184,7 +9083,7 @@ function validateRubricWeights(rubric) {
|
|
|
9184
9083
|
* judgment-task inputs. None of those were machine-verifiable
|
|
9185
9084
|
* end-to-end.
|
|
9186
9085
|
*
|
|
9187
|
-
* This module defines a single, content-addressable envelope
|
|
9086
|
+
* This module defines a single, content-addressable envelope a proposer
|
|
9188
9087
|
* attaches to any task type. It has four orthogonal sections — pick
|
|
9189
9088
|
* whichever apply per task type:
|
|
9190
9089
|
*
|
|
@@ -9218,7 +9117,7 @@ function validateRubricWeights(rubric) {
|
|
|
9218
9117
|
* spec for the judge.
|
|
9219
9118
|
*
|
|
9220
9119
|
* The clean chain: producer task with `successCriteria` → producer
|
|
9221
|
-
* self-assesses honestly →
|
|
9120
|
+
* self-assesses honestly → proposer (or automation) creates a downstream
|
|
9222
9121
|
* judgment task that references the same `successCriteria` (or a
|
|
9223
9122
|
* stricter rubric) → judgment task delivers the binding verdict.
|
|
9224
9123
|
*
|
|
@@ -9380,8 +9279,9 @@ var AssessBriefOutput = Type$1.Object({
|
|
|
9380
9279
|
* - `targetTaskId` resolves to a real task the caller can see.
|
|
9381
9280
|
* - The target is a `fulfill_brief` (you cannot grade an arbitrary
|
|
9382
9281
|
* task type as if it were a brief fulfillment).
|
|
9383
|
-
* -
|
|
9384
|
-
* an
|
|
9282
|
+
* - Unless readiness checks are explicitly deferred, the target is
|
|
9283
|
+
* `completed` with an accepted attempt — grading an in-flight or
|
|
9284
|
+
* failed task would either race or grade nothing.
|
|
9385
9285
|
*
|
|
9386
9286
|
* Agent-distinctness ("assessor ≠ producer") is a runtime / auth-
|
|
9387
9287
|
* layer concern and intentionally NOT checked here. It belongs in
|
|
@@ -9402,7 +9302,7 @@ async function validateAssessBriefInputAsync(input, ctx) {
|
|
|
9402
9302
|
field: "targetTaskId",
|
|
9403
9303
|
message: `targetTaskId ${targetTaskId} is a ${target.taskType}, not a fulfill_brief`
|
|
9404
9304
|
});
|
|
9405
|
-
if (target.status !== "completed" || target.acceptedAttemptN === null) errors.push({
|
|
9305
|
+
if (!ctx.deferReadinessChecks && (target.status !== "completed" || target.acceptedAttemptN === null)) errors.push({
|
|
9406
9306
|
field: "targetTaskId",
|
|
9407
9307
|
message: `targetTaskId ${targetTaskId} is not completed with an accepted attempt (status=${target.status}, acceptedAttemptN=${target.acceptedAttemptN})`
|
|
9408
9308
|
});
|
|
@@ -9476,6 +9376,59 @@ var CuratePackOutput = Type$1.Object({
|
|
|
9476
9376
|
additionalProperties: false
|
|
9477
9377
|
});
|
|
9478
9378
|
//#endregion
|
|
9379
|
+
//#region ../tasks/src/task-types/freeform.ts
|
|
9380
|
+
var FREEFORM_TYPE = "freeform";
|
|
9381
|
+
var FreeformTaskTypeProposal = Type$1.Object({
|
|
9382
|
+
name: Type$1.String({ minLength: 1 }),
|
|
9383
|
+
rationale: Type$1.String({ minLength: 1 }),
|
|
9384
|
+
inputShape: Type$1.Optional(Type$1.Record(Type$1.String(), Type$1.Unknown())),
|
|
9385
|
+
outputShape: Type$1.Optional(Type$1.Record(Type$1.String(), Type$1.Unknown()))
|
|
9386
|
+
}, {
|
|
9387
|
+
$id: "FreeformTaskTypeProposal",
|
|
9388
|
+
additionalProperties: false
|
|
9389
|
+
});
|
|
9390
|
+
var FreeformInput = Type$1.Object({
|
|
9391
|
+
title: Type$1.Optional(Type$1.String({ minLength: 1 })),
|
|
9392
|
+
brief: Type$1.String({ minLength: 1 }),
|
|
9393
|
+
expectedOutput: Type$1.Optional(Type$1.String({ minLength: 1 })),
|
|
9394
|
+
constraints: Type$1.Optional(Type$1.Array(Type$1.String({ minLength: 1 }), { maxItems: 20 })),
|
|
9395
|
+
suggestedTaskType: Type$1.Optional(Type$1.String({ minLength: 1 })),
|
|
9396
|
+
successCriteria: Type$1.Optional(SuccessCriteria),
|
|
9397
|
+
context: Type$1.Optional(TaskContext)
|
|
9398
|
+
}, {
|
|
9399
|
+
$id: "FreeformInput",
|
|
9400
|
+
additionalProperties: false
|
|
9401
|
+
});
|
|
9402
|
+
var FreeformArtifact = Type$1.Object({
|
|
9403
|
+
kind: Type$1.String({ minLength: 1 }),
|
|
9404
|
+
title: Type$1.String({ minLength: 1 }),
|
|
9405
|
+
description: Type$1.Optional(Type$1.String({ minLength: 1 })),
|
|
9406
|
+
url: Type$1.Optional(Type$1.String({ minLength: 1 })),
|
|
9407
|
+
path: Type$1.Optional(Type$1.String({ minLength: 1 }))
|
|
9408
|
+
}, {
|
|
9409
|
+
$id: "FreeformArtifact",
|
|
9410
|
+
additionalProperties: false
|
|
9411
|
+
});
|
|
9412
|
+
var FreeformFollowUpTask = Type$1.Object({
|
|
9413
|
+
title: Type$1.String({ minLength: 1 }),
|
|
9414
|
+
brief: Type$1.String({ minLength: 1 }),
|
|
9415
|
+
suggestedTaskType: Type$1.Optional(Type$1.String({ minLength: 1 }))
|
|
9416
|
+
}, {
|
|
9417
|
+
$id: "FreeformFollowUpTask",
|
|
9418
|
+
additionalProperties: false
|
|
9419
|
+
});
|
|
9420
|
+
var FreeformOutput = Type$1.Object({
|
|
9421
|
+
summary: Type$1.String({ minLength: 1 }),
|
|
9422
|
+
artifacts: Type$1.Optional(Type$1.Array(FreeformArtifact, { maxItems: 20 })),
|
|
9423
|
+
proposedTaskType: Type$1.Optional(FreeformTaskTypeProposal),
|
|
9424
|
+
followUpTasks: Type$1.Optional(Type$1.Array(FreeformFollowUpTask, { maxItems: 20 })),
|
|
9425
|
+
diaryEntryIds: Type$1.Optional(Type$1.Array(Type$1.String({ format: "uuid" }))),
|
|
9426
|
+
verification: Type$1.Optional(VerificationRecord)
|
|
9427
|
+
}, {
|
|
9428
|
+
$id: "FreeformOutput",
|
|
9429
|
+
additionalProperties: false
|
|
9430
|
+
});
|
|
9431
|
+
//#endregion
|
|
9479
9432
|
//#region ../tasks/src/task-types/fulfill-brief.ts
|
|
9480
9433
|
/**
|
|
9481
9434
|
* `fulfill_brief` — produce a signed change against a coding brief.
|
|
@@ -9723,11 +9676,11 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
|
|
|
9723
9676
|
field: "targetTaskId",
|
|
9724
9677
|
message: `targetTaskId=${inp.targetTaskId} is a ${target.taskType}, not a run_eval`
|
|
9725
9678
|
});
|
|
9726
|
-
if (target.status !== "completed" || target.acceptedAttemptN === null) errors.push({
|
|
9679
|
+
if (!ctx.deferReadinessChecks && (target.status !== "completed" || target.acceptedAttemptN === null)) errors.push({
|
|
9727
9680
|
field: "targetTaskId",
|
|
9728
9681
|
message: `targetTaskId=${inp.targetTaskId} is not completed with an accepted attempt (status=${target.status}, acceptedAttemptN=${target.acceptedAttemptN})`
|
|
9729
9682
|
});
|
|
9730
|
-
else if (target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
|
|
9683
|
+
else if (target.acceptedAttemptN !== null && target.acceptedAttemptN !== inp.targetAttemptN) errors.push({
|
|
9731
9684
|
field: "targetAttemptN",
|
|
9732
9685
|
message: `targetAttemptN=${inp.targetAttemptN} does not match the producer's acceptedAttemptN=${target.acceptedAttemptN}`
|
|
9733
9686
|
});
|
|
@@ -9738,6 +9691,7 @@ async function validateJudgeEvalAttemptInputAsync(input, ctx) {
|
|
|
9738
9691
|
if (errors.length > 0 || !target.correlationId) return errors;
|
|
9739
9692
|
const rubric = inp.successCriteria.rubric;
|
|
9740
9693
|
const duplicate = (await ctx.listTasksByCorrelation(target.correlationId)).find((task) => {
|
|
9694
|
+
if (task.id === ctx.currentTaskId) return false;
|
|
9741
9695
|
if (task.taskType !== "judge_eval_attempt") return false;
|
|
9742
9696
|
if (task.status === "failed" || task.status === "cancelled" || task.status === "expired") return false;
|
|
9743
9697
|
const existing = task.input;
|
|
@@ -10033,6 +9987,16 @@ function requireVerificationWhenCriteriaPresent(output, input) {
|
|
|
10033
9987
|
* / claiming a task.
|
|
10034
9988
|
*/
|
|
10035
9989
|
var BUILT_IN_TASK_TYPES = {
|
|
9990
|
+
[FREEFORM_TYPE]: {
|
|
9991
|
+
name: FREEFORM_TYPE,
|
|
9992
|
+
inputSchema: FreeformInput,
|
|
9993
|
+
outputSchema: FreeformOutput,
|
|
9994
|
+
outputKind: "artifact",
|
|
9995
|
+
workspaceScope: "attempt",
|
|
9996
|
+
sessionScope: "none",
|
|
9997
|
+
requiresReferences: false,
|
|
9998
|
+
validateOutput: requireVerificationWhenCriteriaPresent
|
|
9999
|
+
},
|
|
10036
10000
|
[FULFILL_BRIEF_TYPE]: {
|
|
10037
10001
|
name: FULFILL_BRIEF_TYPE,
|
|
10038
10002
|
inputSchema: FulfillBriefInput,
|
|
@@ -10205,11 +10169,12 @@ function taskTypeUsesSubagents(taskType) {
|
|
|
10205
10169
|
*
|
|
10206
10170
|
* Identity rule:
|
|
10207
10171
|
* - claim/execute/sign → agent-only (`task_attempts.claimed_by_agent_id`)
|
|
10208
|
-
* -
|
|
10172
|
+
* - propose/cancel → agent XOR human (dual nullable FK + XOR check)
|
|
10209
10173
|
*
|
|
10210
10174
|
* See GH issue #852 for the full design snapshot.
|
|
10211
10175
|
*/
|
|
10212
10176
|
var TaskStatus = Type$1.Union([
|
|
10177
|
+
Type$1.Literal("waiting"),
|
|
10213
10178
|
Type$1.Literal("queued"),
|
|
10214
10179
|
Type$1.Literal("dispatched"),
|
|
10215
10180
|
Type$1.Literal("running"),
|
|
@@ -10252,6 +10217,36 @@ var TaskMessageKind = Type$1.Union([
|
|
|
10252
10217
|
var Uuid = Type$1.String({ format: "uuid" });
|
|
10253
10218
|
var Cid = Type$1.String({ minLength: 1 });
|
|
10254
10219
|
var IsoTimestamp = Type$1.String({ format: "date-time" });
|
|
10220
|
+
var MAX_CLAIM_CONDITION_BRANCHES = 8;
|
|
10221
|
+
var MAX_CLAIM_CONDITION_STATUSES = 8;
|
|
10222
|
+
var ClaimCondition = Type$1.Recursive((Self) => Type$1.Union([
|
|
10223
|
+
Type$1.Object({
|
|
10224
|
+
op: Type$1.Literal("all"),
|
|
10225
|
+
conditions: Type$1.Array(Self, {
|
|
10226
|
+
minItems: 1,
|
|
10227
|
+
maxItems: MAX_CLAIM_CONDITION_BRANCHES
|
|
10228
|
+
})
|
|
10229
|
+
}, { additionalProperties: false }),
|
|
10230
|
+
Type$1.Object({
|
|
10231
|
+
op: Type$1.Literal("any"),
|
|
10232
|
+
conditions: Type$1.Array(Self, {
|
|
10233
|
+
minItems: 1,
|
|
10234
|
+
maxItems: MAX_CLAIM_CONDITION_BRANCHES
|
|
10235
|
+
})
|
|
10236
|
+
}, { additionalProperties: false }),
|
|
10237
|
+
Type$1.Object({
|
|
10238
|
+
op: Type$1.Literal("task_status"),
|
|
10239
|
+
taskId: Uuid,
|
|
10240
|
+
statuses: Type$1.Array(Type$1.Ref(TaskStatus), {
|
|
10241
|
+
minItems: 1,
|
|
10242
|
+
maxItems: MAX_CLAIM_CONDITION_STATUSES
|
|
10243
|
+
})
|
|
10244
|
+
}, { additionalProperties: false }),
|
|
10245
|
+
Type$1.Object({
|
|
10246
|
+
op: Type$1.Literal("task_accepted"),
|
|
10247
|
+
taskId: Uuid
|
|
10248
|
+
}, { additionalProperties: false })
|
|
10249
|
+
]), { $id: "ClaimCondition" });
|
|
10255
10250
|
/**
|
|
10256
10251
|
* Reference to another task's output or an external artifact.
|
|
10257
10252
|
* Embedded in `tasks.references` JSONB array.
|
|
@@ -10328,9 +10323,10 @@ Type$1.Object({
|
|
|
10328
10323
|
inputCid: Cid,
|
|
10329
10324
|
references: Type$1.Array(TaskRef),
|
|
10330
10325
|
correlationId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
10331
|
-
|
|
10332
|
-
|
|
10326
|
+
proposedByAgentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
10327
|
+
proposedByHumanId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
10333
10328
|
acceptedAttemptN: Type$1.Union([Type$1.Number(), Type$1.Null()]),
|
|
10329
|
+
claimCondition: Type$1.Union([ClaimCondition, Type$1.Null()]),
|
|
10334
10330
|
requiredExecutorTrustLevel: ExecutorTrustLevel,
|
|
10335
10331
|
allowedExecutors: Type$1.Array(ExecutorRef, { maxItems: 16 }),
|
|
10336
10332
|
status: TaskStatus,
|
|
@@ -10787,7 +10783,7 @@ function buildCuratePackUserPrompt(input, ctx) {
|
|
|
10787
10783
|
"to defend it in the summary."
|
|
10788
10784
|
].join("\n");
|
|
10789
10785
|
const constraintsLines = [];
|
|
10790
|
-
if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by
|
|
10786
|
+
if (entryTypesPinned) constraintsLines.push(`- Entry types pinned by proposer (do not widen): ${entryTypes.map((t) => `\`${t}\``).join(", ")}`);
|
|
10791
10787
|
else constraintsLines.push("- Entry types: **you choose**. The diary contains three kinds:", " - `episodic` — incident reports, \"what happened and how we fixed it\" narratives.", " - `semantic` — durable decisions, patterns, design rationale.", " - `procedural` — commit audit trails / changelog-style provenance.", " Pick the subset that fits the prompt. For \"failures and workarounds\"", " or \"decisions we made\" you generally do NOT want `procedural` — those", " entries are append-only commit logs and produce changelog-shaped packs.", " Include `procedural` only when the prompt explicitly asks for changelog-", " style content (e.g., \"what shipped this week\"). State your choice", " briefly in the final `summary`.");
|
|
10792
10788
|
constraintsLines.push(`- Recipe tag: \`${resolvedRecipe}\` (recorded on pack params)`);
|
|
10793
10789
|
constraintsLines.push(tokenBudget ? `- Token budget (soft cap on final pack): ${tokenBudget}. Pick entry count so the pack fits — estimate ~300 tok/entry as a starting heuristic, tighten after inspecting actual content lengths.` : "- No token budget — size the pack to match the prompt, not an arbitrary target.");
|
|
@@ -10933,6 +10929,97 @@ function buildCuratePackUserPrompt(input, ctx) {
|
|
|
10933
10929
|
]);
|
|
10934
10930
|
}
|
|
10935
10931
|
//#endregion
|
|
10932
|
+
//#region ../agent-runtime/src/prompts/freeform.ts
|
|
10933
|
+
function buildFreeformUserPrompt(input, ctx) {
|
|
10934
|
+
const header = [
|
|
10935
|
+
"# Freeform Task Agent",
|
|
10936
|
+
"",
|
|
10937
|
+
"You are handling an exploratory MoltNet task that does not yet have a",
|
|
10938
|
+
"more specific execution contract. Treat the brief as the source of truth,",
|
|
10939
|
+
"use judgment, and keep the result useful enough for a human or another",
|
|
10940
|
+
"agent to continue from it.",
|
|
10941
|
+
"",
|
|
10942
|
+
`Task id: \`${ctx.taskId}\``
|
|
10943
|
+
].join("\n");
|
|
10944
|
+
const expectedOutput = input.expectedOutput ?? "";
|
|
10945
|
+
const constraints = input.constraints?.length ? input.constraints.map((constraint) => `- ${constraint}`).join("\n") : "";
|
|
10946
|
+
const suggestedTaskType = input.suggestedTaskType ? [`The proposer suggested task type \`${input.suggestedTaskType}\`.`, "Use it as a hint, not as a contract."].join("\n") : "";
|
|
10947
|
+
const workflow = [
|
|
10948
|
+
"1. Clarify the real objective from the brief before acting.",
|
|
10949
|
+
"2. Gather enough context to avoid guessing.",
|
|
10950
|
+
"3. Complete the requested work when it is safe and bounded.",
|
|
10951
|
+
"4. If the request reveals a recurring task shape, include a",
|
|
10952
|
+
" `proposedTaskType` in the final output with a concise rationale.",
|
|
10953
|
+
"5. If the work should be split or continued, include `followUpTasks`."
|
|
10954
|
+
].join("\n");
|
|
10955
|
+
return assembleTaskPrompt("freeform", [
|
|
10956
|
+
{
|
|
10957
|
+
id: "freeform.header",
|
|
10958
|
+
source: "header",
|
|
10959
|
+
body: header
|
|
10960
|
+
},
|
|
10961
|
+
{
|
|
10962
|
+
id: "freeform.title",
|
|
10963
|
+
source: "task_input",
|
|
10964
|
+
header: "Title",
|
|
10965
|
+
body: input.title ?? ""
|
|
10966
|
+
},
|
|
10967
|
+
{
|
|
10968
|
+
id: "freeform.brief",
|
|
10969
|
+
source: "task_input",
|
|
10970
|
+
header: "Brief",
|
|
10971
|
+
body: input.brief
|
|
10972
|
+
},
|
|
10973
|
+
{
|
|
10974
|
+
id: "freeform.expected_output",
|
|
10975
|
+
source: "task_input",
|
|
10976
|
+
header: "Expected Output",
|
|
10977
|
+
body: expectedOutput
|
|
10978
|
+
},
|
|
10979
|
+
{
|
|
10980
|
+
id: "freeform.constraints",
|
|
10981
|
+
source: "task_input",
|
|
10982
|
+
header: "Constraints",
|
|
10983
|
+
body: constraints
|
|
10984
|
+
},
|
|
10985
|
+
{
|
|
10986
|
+
id: "freeform.suggested_task_type",
|
|
10987
|
+
source: "task_input",
|
|
10988
|
+
header: "Suggested Task Type",
|
|
10989
|
+
body: suggestedTaskType
|
|
10990
|
+
},
|
|
10991
|
+
{
|
|
10992
|
+
id: "freeform.workflow",
|
|
10993
|
+
source: "static",
|
|
10994
|
+
header: "Workflow",
|
|
10995
|
+
body: workflow
|
|
10996
|
+
},
|
|
10997
|
+
{
|
|
10998
|
+
id: "freeform.verification",
|
|
10999
|
+
source: "verification",
|
|
11000
|
+
body: buildSelfVerificationBlock(ctx.taskId)
|
|
11001
|
+
},
|
|
11002
|
+
{
|
|
11003
|
+
id: "freeform.final_output",
|
|
11004
|
+
source: "final_output",
|
|
11005
|
+
body: buildFinalOutputBlock({
|
|
11006
|
+
taskType: "freeform",
|
|
11007
|
+
outputSchemaName: "FreeformOutput",
|
|
11008
|
+
shapeSketch: [
|
|
11009
|
+
"{",
|
|
11010
|
+
" \"summary\": \"<2-5 sentence result>\",",
|
|
11011
|
+
" \"artifacts\": [{ \"kind\": \"...\", \"title\": \"...\", \"description\": \"...\", \"url\": \"...\", \"path\": \"...\" }],",
|
|
11012
|
+
" \"proposedTaskType\": { \"name\": \"...\", \"rationale\": \"...\", \"inputShape\": {}, \"outputShape\": {} },",
|
|
11013
|
+
" \"followUpTasks\": [{ \"title\": \"...\", \"brief\": \"...\", \"suggestedTaskType\": \"...\" }],",
|
|
11014
|
+
" \"diaryEntryIds\": [\"...\"],",
|
|
11015
|
+
" \"verification\": <required iff input.successCriteria; see Self-verification>",
|
|
11016
|
+
"}"
|
|
11017
|
+
].join("\n")
|
|
11018
|
+
})
|
|
11019
|
+
}
|
|
11020
|
+
]);
|
|
11021
|
+
}
|
|
11022
|
+
//#endregion
|
|
10936
11023
|
//#region ../agent-runtime/src/prompts/fulfill-brief.ts
|
|
10937
11024
|
/**
|
|
10938
11025
|
* Build the first user-message prompt for a `fulfill_brief` task.
|
|
@@ -10982,7 +11069,11 @@ function buildFulfillBriefUserPrompt(input, ctx) {
|
|
|
10982
11069
|
"5. For every commit, create a signed diary entry first via",
|
|
10983
11070
|
" `moltnet_create_entry` and embed its id in the commit trailer",
|
|
10984
11071
|
" `MoltNet-Diary: <id>` (per the runtime instructor).",
|
|
10985
|
-
"6. Push the branch and open a PR
|
|
11072
|
+
"6. Push the branch and open a PR — run `git push` and `gh pr create`",
|
|
11073
|
+
" IN the VM with your normal `bash` tool (use the",
|
|
11074
|
+
" `GH_TOKEN=$(moltnet github token …) gh …` form from the runtime",
|
|
11075
|
+
" instructor). Do NOT use `moltnet_host_exec` for this; it needs human",
|
|
11076
|
+
" approval that is unavailable in a headless run."
|
|
10986
11077
|
].join("\n");
|
|
10987
11078
|
return assembleTaskPrompt("fulfill_brief", [
|
|
10988
11079
|
{
|
|
@@ -11682,6 +11773,12 @@ function buildRunEvalUserPrompt(input, ctx) {
|
|
|
11682
11773
|
*/
|
|
11683
11774
|
function buildTaskUserPrompt(task, ctx) {
|
|
11684
11775
|
switch (task.taskType) {
|
|
11776
|
+
case FREEFORM_TYPE:
|
|
11777
|
+
if (!Value.Check(FreeformInput, task.input)) {
|
|
11778
|
+
const errors = [...Value.Errors(FreeformInput, task.input)];
|
|
11779
|
+
throw new Error(`freeform input failed validation: ${JSON.stringify(errors.slice(0, 3))}`);
|
|
11780
|
+
}
|
|
11781
|
+
return buildFreeformUserPrompt(task.input, { taskId: ctx.taskId });
|
|
11685
11782
|
case FULFILL_BRIEF_TYPE:
|
|
11686
11783
|
if (!Value.Check(FulfillBriefInput, task.input)) {
|
|
11687
11784
|
const errors = [...Value.Errors(FulfillBriefInput, task.input)];
|
|
@@ -15419,6 +15516,11 @@ function buildRuntimeInstructor(ctx) {
|
|
|
15419
15516
|
"",
|
|
15420
15517
|
"- `git push` uses the gitconfig-configured credential helper and is not",
|
|
15421
15518
|
" a `gh` call — it does not need `GH_TOKEN`.",
|
|
15519
|
+
"- Run `git` and `gh` in the VM with your normal `bash` tool — your",
|
|
15520
|
+
" credentials are injected here, so they work in the guest. The",
|
|
15521
|
+
" `moltnet_host_exec` tool is a last-resort host escape-hatch that",
|
|
15522
|
+
" requires human approval and is unavailable in headless task runs;",
|
|
15523
|
+
" never use it for routine git/gh.",
|
|
15422
15524
|
"",
|
|
15423
15525
|
"## Diary discipline",
|
|
15424
15526
|
"",
|
|
@@ -16594,7 +16696,7 @@ async function executePiTask(claimedTask, reporter, opts) {
|
|
|
16594
16696
|
durationMs: Date.now() - startTime,
|
|
16595
16697
|
error: {
|
|
16596
16698
|
code: "task_cancelled",
|
|
16597
|
-
message: reporter.cancelReason ?? "Task cancelled by
|
|
16699
|
+
message: reporter.cancelReason ?? "Task cancelled by proposer while pi session was running.",
|
|
16598
16700
|
retryable: false
|
|
16599
16701
|
}
|
|
16600
16702
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/pi-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoltNet pi extension — sandboxed tool execution in Gondolin VMs with MoltNet identity and persistent memory",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@earendil-works/gondolin": "^0.9.1",
|
|
32
32
|
"@opentelemetry/api": "^1.9.0",
|
|
33
33
|
"@sinclair/typebox": "^0.34.0",
|
|
34
|
-
"@themoltnet/agent-runtime": "0.
|
|
35
|
-
"@themoltnet/sdk": "0.
|
|
34
|
+
"@themoltnet/agent-runtime": "0.19.1",
|
|
35
|
+
"@themoltnet/sdk": "0.106.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@earendil-works/pi-coding-agent": ">=0.74.0",
|