@themoltnet/pi-extension 0.4.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/README.md +204 -41
- package/dist/index.d.ts +185 -7
- package/dist/index.js +1293 -700
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -13,7 +13,6 @@ import { RealFSProvider, ShadowProvider, VM, VmCheckpoint, createHttpHooks, crea
|
|
|
13
13
|
import { parseEnv } from "node:util";
|
|
14
14
|
import { FormatRegistry, Type as Type$1 } from "@sinclair/typebox";
|
|
15
15
|
import { Value } from "@sinclair/typebox/value";
|
|
16
|
-
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
17
16
|
//#region ../api-client/src/generated/core/bodySerializer.gen.ts
|
|
18
17
|
var jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
|
|
19
18
|
Object.entries({
|
|
@@ -2039,6 +2038,276 @@ var getLegreffierOnboardingStatus = (options) => (options.client ?? client).get(
|
|
|
2039
2038
|
...options
|
|
2040
2039
|
});
|
|
2041
2040
|
/**
|
|
2041
|
+
* List tasks for a team with optional filters.
|
|
2042
|
+
*/
|
|
2043
|
+
var listTasks = (options) => (options.client ?? client).get({
|
|
2044
|
+
security: [
|
|
2045
|
+
{
|
|
2046
|
+
scheme: "bearer",
|
|
2047
|
+
type: "http"
|
|
2048
|
+
},
|
|
2049
|
+
{
|
|
2050
|
+
name: "X-Moltnet-Session-Token",
|
|
2051
|
+
type: "apiKey"
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
in: "cookie",
|
|
2055
|
+
name: "ory_kratos_session",
|
|
2056
|
+
type: "apiKey"
|
|
2057
|
+
}
|
|
2058
|
+
],
|
|
2059
|
+
url: "/tasks",
|
|
2060
|
+
...options
|
|
2061
|
+
});
|
|
2062
|
+
/**
|
|
2063
|
+
* Create and enqueue a new task.
|
|
2064
|
+
*/
|
|
2065
|
+
var createTask = (options) => (options.client ?? client).post({
|
|
2066
|
+
security: [
|
|
2067
|
+
{
|
|
2068
|
+
scheme: "bearer",
|
|
2069
|
+
type: "http"
|
|
2070
|
+
},
|
|
2071
|
+
{
|
|
2072
|
+
name: "X-Moltnet-Session-Token",
|
|
2073
|
+
type: "apiKey"
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
in: "cookie",
|
|
2077
|
+
name: "ory_kratos_session",
|
|
2078
|
+
type: "apiKey"
|
|
2079
|
+
}
|
|
2080
|
+
],
|
|
2081
|
+
url: "/tasks",
|
|
2082
|
+
...options,
|
|
2083
|
+
headers: {
|
|
2084
|
+
"Content-Type": "application/json",
|
|
2085
|
+
...options.headers
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
/**
|
|
2089
|
+
* Get a task by ID.
|
|
2090
|
+
*/
|
|
2091
|
+
var getTask = (options) => (options.client ?? client).get({
|
|
2092
|
+
security: [
|
|
2093
|
+
{
|
|
2094
|
+
scheme: "bearer",
|
|
2095
|
+
type: "http"
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
name: "X-Moltnet-Session-Token",
|
|
2099
|
+
type: "apiKey"
|
|
2100
|
+
},
|
|
2101
|
+
{
|
|
2102
|
+
in: "cookie",
|
|
2103
|
+
name: "ory_kratos_session",
|
|
2104
|
+
type: "apiKey"
|
|
2105
|
+
}
|
|
2106
|
+
],
|
|
2107
|
+
url: "/tasks/{id}",
|
|
2108
|
+
...options
|
|
2109
|
+
});
|
|
2110
|
+
/**
|
|
2111
|
+
* Claim a queued task and start an attempt.
|
|
2112
|
+
*/
|
|
2113
|
+
var claimTask = (options) => (options.client ?? client).post({
|
|
2114
|
+
security: [
|
|
2115
|
+
{
|
|
2116
|
+
scheme: "bearer",
|
|
2117
|
+
type: "http"
|
|
2118
|
+
},
|
|
2119
|
+
{
|
|
2120
|
+
name: "X-Moltnet-Session-Token",
|
|
2121
|
+
type: "apiKey"
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
2124
|
+
in: "cookie",
|
|
2125
|
+
name: "ory_kratos_session",
|
|
2126
|
+
type: "apiKey"
|
|
2127
|
+
}
|
|
2128
|
+
],
|
|
2129
|
+
url: "/tasks/{id}/claim",
|
|
2130
|
+
...options,
|
|
2131
|
+
headers: {
|
|
2132
|
+
"Content-Type": "application/json",
|
|
2133
|
+
...options.headers
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
/**
|
|
2137
|
+
* Send a heartbeat to keep the attempt lease alive.
|
|
2138
|
+
*/
|
|
2139
|
+
var taskHeartbeat = (options) => (options.client ?? client).post({
|
|
2140
|
+
security: [
|
|
2141
|
+
{
|
|
2142
|
+
scheme: "bearer",
|
|
2143
|
+
type: "http"
|
|
2144
|
+
},
|
|
2145
|
+
{
|
|
2146
|
+
name: "X-Moltnet-Session-Token",
|
|
2147
|
+
type: "apiKey"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
in: "cookie",
|
|
2151
|
+
name: "ory_kratos_session",
|
|
2152
|
+
type: "apiKey"
|
|
2153
|
+
}
|
|
2154
|
+
],
|
|
2155
|
+
url: "/tasks/{id}/attempts/{n}/heartbeat",
|
|
2156
|
+
...options,
|
|
2157
|
+
headers: {
|
|
2158
|
+
"Content-Type": "application/json",
|
|
2159
|
+
...options.headers
|
|
2160
|
+
}
|
|
2161
|
+
});
|
|
2162
|
+
/**
|
|
2163
|
+
* Mark an attempt as completed with output.
|
|
2164
|
+
*/
|
|
2165
|
+
var completeTask = (options) => (options.client ?? client).post({
|
|
2166
|
+
security: [
|
|
2167
|
+
{
|
|
2168
|
+
scheme: "bearer",
|
|
2169
|
+
type: "http"
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
name: "X-Moltnet-Session-Token",
|
|
2173
|
+
type: "apiKey"
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
in: "cookie",
|
|
2177
|
+
name: "ory_kratos_session",
|
|
2178
|
+
type: "apiKey"
|
|
2179
|
+
}
|
|
2180
|
+
],
|
|
2181
|
+
url: "/tasks/{id}/attempts/{n}/complete",
|
|
2182
|
+
...options,
|
|
2183
|
+
headers: {
|
|
2184
|
+
"Content-Type": "application/json",
|
|
2185
|
+
...options.headers
|
|
2186
|
+
}
|
|
2187
|
+
});
|
|
2188
|
+
/**
|
|
2189
|
+
* Mark an attempt as failed with error details.
|
|
2190
|
+
*/
|
|
2191
|
+
var failTask = (options) => (options.client ?? client).post({
|
|
2192
|
+
security: [
|
|
2193
|
+
{
|
|
2194
|
+
scheme: "bearer",
|
|
2195
|
+
type: "http"
|
|
2196
|
+
},
|
|
2197
|
+
{
|
|
2198
|
+
name: "X-Moltnet-Session-Token",
|
|
2199
|
+
type: "apiKey"
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
in: "cookie",
|
|
2203
|
+
name: "ory_kratos_session",
|
|
2204
|
+
type: "apiKey"
|
|
2205
|
+
}
|
|
2206
|
+
],
|
|
2207
|
+
url: "/tasks/{id}/attempts/{n}/fail",
|
|
2208
|
+
...options,
|
|
2209
|
+
headers: {
|
|
2210
|
+
"Content-Type": "application/json",
|
|
2211
|
+
...options.headers
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
/**
|
|
2215
|
+
* Cancel a task.
|
|
2216
|
+
*/
|
|
2217
|
+
var cancelTask = (options) => (options.client ?? client).post({
|
|
2218
|
+
security: [
|
|
2219
|
+
{
|
|
2220
|
+
scheme: "bearer",
|
|
2221
|
+
type: "http"
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
name: "X-Moltnet-Session-Token",
|
|
2225
|
+
type: "apiKey"
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
in: "cookie",
|
|
2229
|
+
name: "ory_kratos_session",
|
|
2230
|
+
type: "apiKey"
|
|
2231
|
+
}
|
|
2232
|
+
],
|
|
2233
|
+
url: "/tasks/{id}/cancel",
|
|
2234
|
+
...options,
|
|
2235
|
+
headers: {
|
|
2236
|
+
"Content-Type": "application/json",
|
|
2237
|
+
...options.headers
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
/**
|
|
2241
|
+
* List all attempts for a task.
|
|
2242
|
+
*/
|
|
2243
|
+
var listTaskAttempts = (options) => (options.client ?? client).get({
|
|
2244
|
+
security: [
|
|
2245
|
+
{
|
|
2246
|
+
scheme: "bearer",
|
|
2247
|
+
type: "http"
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
name: "X-Moltnet-Session-Token",
|
|
2251
|
+
type: "apiKey"
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
in: "cookie",
|
|
2255
|
+
name: "ory_kratos_session",
|
|
2256
|
+
type: "apiKey"
|
|
2257
|
+
}
|
|
2258
|
+
],
|
|
2259
|
+
url: "/tasks/{id}/attempts",
|
|
2260
|
+
...options
|
|
2261
|
+
});
|
|
2262
|
+
/**
|
|
2263
|
+
* List messages for a task attempt.
|
|
2264
|
+
*/
|
|
2265
|
+
var listTaskMessages = (options) => (options.client ?? client).get({
|
|
2266
|
+
security: [
|
|
2267
|
+
{
|
|
2268
|
+
scheme: "bearer",
|
|
2269
|
+
type: "http"
|
|
2270
|
+
},
|
|
2271
|
+
{
|
|
2272
|
+
name: "X-Moltnet-Session-Token",
|
|
2273
|
+
type: "apiKey"
|
|
2274
|
+
},
|
|
2275
|
+
{
|
|
2276
|
+
in: "cookie",
|
|
2277
|
+
name: "ory_kratos_session",
|
|
2278
|
+
type: "apiKey"
|
|
2279
|
+
}
|
|
2280
|
+
],
|
|
2281
|
+
url: "/tasks/{id}/attempts/{n}/messages",
|
|
2282
|
+
...options
|
|
2283
|
+
});
|
|
2284
|
+
/**
|
|
2285
|
+
* Append messages to a task attempt.
|
|
2286
|
+
*/
|
|
2287
|
+
var appendTaskMessages = (options) => (options.client ?? client).post({
|
|
2288
|
+
security: [
|
|
2289
|
+
{
|
|
2290
|
+
scheme: "bearer",
|
|
2291
|
+
type: "http"
|
|
2292
|
+
},
|
|
2293
|
+
{
|
|
2294
|
+
name: "X-Moltnet-Session-Token",
|
|
2295
|
+
type: "apiKey"
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
in: "cookie",
|
|
2299
|
+
name: "ory_kratos_session",
|
|
2300
|
+
type: "apiKey"
|
|
2301
|
+
}
|
|
2302
|
+
],
|
|
2303
|
+
url: "/tasks/{id}/attempts/{n}/messages",
|
|
2304
|
+
...options,
|
|
2305
|
+
headers: {
|
|
2306
|
+
"Content-Type": "application/json",
|
|
2307
|
+
...options.headers
|
|
2308
|
+
}
|
|
2309
|
+
});
|
|
2310
|
+
/**
|
|
2042
2311
|
* List all problem types used in API error responses (RFC 9457).
|
|
2043
2312
|
*/
|
|
2044
2313
|
var listProblemTypes = (options) => (options?.client ?? client).get({
|
|
@@ -3059,7 +3328,7 @@ function decode$3(string, alphabetIdx, bitsPerChar, name) {
|
|
|
3059
3328
|
if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) throw new SyntaxError("Unexpected end of data");
|
|
3060
3329
|
return out;
|
|
3061
3330
|
}
|
|
3062
|
-
function encode$
|
|
3331
|
+
function encode$2(data, alphabet, bitsPerChar) {
|
|
3063
3332
|
const pad = alphabet[alphabet.length - 1] === "=";
|
|
3064
3333
|
const mask = (1 << bitsPerChar) - 1;
|
|
3065
3334
|
let out = "";
|
|
@@ -3091,7 +3360,7 @@ function rfc4648({ name, prefix, bitsPerChar, alphabet }) {
|
|
|
3091
3360
|
prefix,
|
|
3092
3361
|
name,
|
|
3093
3362
|
encode(input) {
|
|
3094
|
-
return encode$
|
|
3363
|
+
return encode$2(input, alphabet, bitsPerChar);
|
|
3095
3364
|
},
|
|
3096
3365
|
decode(input) {
|
|
3097
3366
|
return decode$3(input, alphabetIdx, bitsPerChar, name);
|
|
@@ -3180,14 +3449,14 @@ baseX({
|
|
|
3180
3449
|
});
|
|
3181
3450
|
//#endregion
|
|
3182
3451
|
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/vendor/varint.js
|
|
3183
|
-
var encode_1 = encode;
|
|
3452
|
+
var encode_1 = encode$1;
|
|
3184
3453
|
var MSB = 128, MSBALL = -128, INT = Math.pow(2, 31);
|
|
3185
3454
|
/**
|
|
3186
3455
|
* @param {number} num
|
|
3187
3456
|
* @param {number[]} out
|
|
3188
3457
|
* @param {number} offset
|
|
3189
3458
|
*/
|
|
3190
|
-
function encode(num, out, offset) {
|
|
3459
|
+
function encode$1(num, out, offset) {
|
|
3191
3460
|
out = out || [];
|
|
3192
3461
|
offset = offset || 0;
|
|
3193
3462
|
var oldOffset = offset;
|
|
@@ -3200,7 +3469,7 @@ function encode(num, out, offset) {
|
|
|
3200
3469
|
num >>>= 7;
|
|
3201
3470
|
}
|
|
3202
3471
|
out[offset] = num | 0;
|
|
3203
|
-
encode.bytes = offset - oldOffset + 1;
|
|
3472
|
+
encode$1.bytes = offset - oldOffset + 1;
|
|
3204
3473
|
return out;
|
|
3205
3474
|
}
|
|
3206
3475
|
var decode$2 = read;
|
|
@@ -4069,8 +4338,13 @@ etc.sha512Sync = (...m) => {
|
|
|
4069
4338
|
m.forEach((msg) => hash.update(msg));
|
|
4070
4339
|
return hash.digest();
|
|
4071
4340
|
};
|
|
4072
|
-
|
|
4341
|
+
//#endregion
|
|
4342
|
+
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/codecs/json.js
|
|
4343
|
+
var textEncoder$1 = new TextEncoder();
|
|
4073
4344
|
new TextDecoder();
|
|
4345
|
+
function encode(node) {
|
|
4346
|
+
return textEncoder$1.encode(JSON.stringify(node));
|
|
4347
|
+
}
|
|
4074
4348
|
//#endregion
|
|
4075
4349
|
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/hashes/hasher.js
|
|
4076
4350
|
var DEFAULT_MIN_DIGEST_LENGTH = 20;
|
|
@@ -4117,7 +4391,9 @@ function createDigest(digest, code, truncate) {
|
|
|
4117
4391
|
}
|
|
4118
4392
|
return create(code, digest);
|
|
4119
4393
|
}
|
|
4120
|
-
|
|
4394
|
+
//#endregion
|
|
4395
|
+
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/hashes/sha2.js
|
|
4396
|
+
var sha256 = from({
|
|
4121
4397
|
name: "sha2-256",
|
|
4122
4398
|
code: 18,
|
|
4123
4399
|
encode: (input) => coerce(crypto.createHash("sha256").update(input).digest())
|
|
@@ -4128,6 +4404,20 @@ from({
|
|
|
4128
4404
|
encode: (input) => coerce(crypto.createHash("sha512").update(input).digest())
|
|
4129
4405
|
});
|
|
4130
4406
|
//#endregion
|
|
4407
|
+
//#region ../crypto-service/src/json-cid.ts
|
|
4408
|
+
/**
|
|
4409
|
+
* Generic JSON CID — CIDv1 for arbitrary JSON-serialisable values.
|
|
4410
|
+
*
|
|
4411
|
+
* Uses the dag-json codec and sha2-256, producing a base32lower CIDv1.
|
|
4412
|
+
* Suitable for content-addressing task inputs, schema objects, and other
|
|
4413
|
+
* JSON payloads that don't need diary-entry canonical normalisation.
|
|
4414
|
+
*/
|
|
4415
|
+
async function computeJsonCid(value) {
|
|
4416
|
+
const bytes = encode(value);
|
|
4417
|
+
const hash = await sha256.digest(bytes);
|
|
4418
|
+
return CID.create(1, 512, hash).toString();
|
|
4419
|
+
}
|
|
4420
|
+
//#endregion
|
|
4131
4421
|
//#region ../../node_modules/.pnpm/cborg@4.5.8/node_modules/cborg/lib/is.js
|
|
4132
4422
|
var objectTypeNames = [
|
|
4133
4423
|
"Object",
|
|
@@ -6302,18 +6592,124 @@ function createSigningRequestsNamespace(context) {
|
|
|
6302
6592
|
};
|
|
6303
6593
|
}
|
|
6304
6594
|
//#endregion
|
|
6305
|
-
//#region ../sdk/src/namespaces/
|
|
6306
|
-
function
|
|
6595
|
+
//#region ../sdk/src/namespaces/tasks.ts
|
|
6596
|
+
function createTasksNamespace(context) {
|
|
6307
6597
|
const { client, auth } = context;
|
|
6308
6598
|
return {
|
|
6309
|
-
async list() {
|
|
6310
|
-
return unwrapResult(await
|
|
6599
|
+
async list(query) {
|
|
6600
|
+
return unwrapResult(await listTasks({
|
|
6311
6601
|
client,
|
|
6312
|
-
auth
|
|
6602
|
+
auth,
|
|
6603
|
+
query
|
|
6313
6604
|
}));
|
|
6314
6605
|
},
|
|
6315
|
-
async
|
|
6316
|
-
return unwrapResult(await
|
|
6606
|
+
async create(body) {
|
|
6607
|
+
return unwrapResult(await createTask({
|
|
6608
|
+
client,
|
|
6609
|
+
auth,
|
|
6610
|
+
body
|
|
6611
|
+
}));
|
|
6612
|
+
},
|
|
6613
|
+
async get(id) {
|
|
6614
|
+
return unwrapResult(await getTask({
|
|
6615
|
+
client,
|
|
6616
|
+
auth,
|
|
6617
|
+
path: { id }
|
|
6618
|
+
}));
|
|
6619
|
+
},
|
|
6620
|
+
async claim(id, body) {
|
|
6621
|
+
return unwrapResult(await claimTask({
|
|
6622
|
+
client,
|
|
6623
|
+
auth,
|
|
6624
|
+
path: { id },
|
|
6625
|
+
body
|
|
6626
|
+
}));
|
|
6627
|
+
},
|
|
6628
|
+
async heartbeat(id, n, body) {
|
|
6629
|
+
return unwrapResult(await taskHeartbeat({
|
|
6630
|
+
client,
|
|
6631
|
+
auth,
|
|
6632
|
+
path: {
|
|
6633
|
+
id,
|
|
6634
|
+
n
|
|
6635
|
+
},
|
|
6636
|
+
body
|
|
6637
|
+
}));
|
|
6638
|
+
},
|
|
6639
|
+
async complete(id, n, body) {
|
|
6640
|
+
return unwrapResult(await completeTask({
|
|
6641
|
+
client,
|
|
6642
|
+
auth,
|
|
6643
|
+
path: {
|
|
6644
|
+
id,
|
|
6645
|
+
n
|
|
6646
|
+
},
|
|
6647
|
+
body
|
|
6648
|
+
}));
|
|
6649
|
+
},
|
|
6650
|
+
async fail(id, n, body) {
|
|
6651
|
+
return unwrapResult(await failTask({
|
|
6652
|
+
client,
|
|
6653
|
+
auth,
|
|
6654
|
+
path: {
|
|
6655
|
+
id,
|
|
6656
|
+
n
|
|
6657
|
+
},
|
|
6658
|
+
body
|
|
6659
|
+
}));
|
|
6660
|
+
},
|
|
6661
|
+
async cancel(id, body) {
|
|
6662
|
+
return unwrapResult(await cancelTask({
|
|
6663
|
+
client,
|
|
6664
|
+
auth,
|
|
6665
|
+
path: { id },
|
|
6666
|
+
body
|
|
6667
|
+
}));
|
|
6668
|
+
},
|
|
6669
|
+
async listAttempts(id) {
|
|
6670
|
+
return unwrapResult(await listTaskAttempts({
|
|
6671
|
+
client,
|
|
6672
|
+
auth,
|
|
6673
|
+
path: { id }
|
|
6674
|
+
}));
|
|
6675
|
+
},
|
|
6676
|
+
async listMessages(id, n, query) {
|
|
6677
|
+
return unwrapResult(await listTaskMessages({
|
|
6678
|
+
client,
|
|
6679
|
+
auth,
|
|
6680
|
+
path: {
|
|
6681
|
+
id,
|
|
6682
|
+
n
|
|
6683
|
+
},
|
|
6684
|
+
query
|
|
6685
|
+
}));
|
|
6686
|
+
},
|
|
6687
|
+
async appendMessages(id, n, body) {
|
|
6688
|
+
return unwrapResult(await appendTaskMessages({
|
|
6689
|
+
client,
|
|
6690
|
+
auth,
|
|
6691
|
+
path: {
|
|
6692
|
+
id,
|
|
6693
|
+
n
|
|
6694
|
+
},
|
|
6695
|
+
body
|
|
6696
|
+
}));
|
|
6697
|
+
}
|
|
6698
|
+
};
|
|
6699
|
+
}
|
|
6700
|
+
//#endregion
|
|
6701
|
+
//#region ../sdk/src/namespaces/teams.ts
|
|
6702
|
+
function createTeamsNamespace(context) {
|
|
6703
|
+
const { client, auth } = context;
|
|
6704
|
+
return {
|
|
6705
|
+
async list() {
|
|
6706
|
+
return unwrapResult(await listTeams({
|
|
6707
|
+
client,
|
|
6708
|
+
auth
|
|
6709
|
+
}));
|
|
6710
|
+
},
|
|
6711
|
+
async get(id) {
|
|
6712
|
+
return unwrapResult(await getTeam({
|
|
6317
6713
|
client,
|
|
6318
6714
|
auth,
|
|
6319
6715
|
path: { id }
|
|
@@ -6433,6 +6829,7 @@ function createAgent(options) {
|
|
|
6433
6829
|
legreffier: createLegreffierNamespace(context),
|
|
6434
6830
|
problems: createProblemsNamespace(context),
|
|
6435
6831
|
teams: createTeamsNamespace(context),
|
|
6832
|
+
tasks: createTasksNamespace(context),
|
|
6436
6833
|
client,
|
|
6437
6834
|
getToken: () => tokenManager.getToken()
|
|
6438
6835
|
};
|
|
@@ -7171,6 +7568,24 @@ function renderPhase6Markdown(pack) {
|
|
|
7171
7568
|
* These tools run on the host (not in the VM) via the MoltNet SDK,
|
|
7172
7569
|
* so agent credentials never touch the VM filesystem.
|
|
7173
7570
|
*/
|
|
7571
|
+
/**
|
|
7572
|
+
* Baseline env keys forwarded to host-exec child processes.
|
|
7573
|
+
* Callers can extend this set at sandbox startup via `MoltNetToolsConfig.hostExecBaseEnv`.
|
|
7574
|
+
*/
|
|
7575
|
+
var HOST_EXEC_DEFAULT_BASE_ENV = new Set([
|
|
7576
|
+
"PATH",
|
|
7577
|
+
"HOME",
|
|
7578
|
+
"LANG",
|
|
7579
|
+
"LC_ALL",
|
|
7580
|
+
"TMPDIR",
|
|
7581
|
+
"GIT_CONFIG_GLOBAL",
|
|
7582
|
+
"MOLTNET_CREDENTIALS_PATH",
|
|
7583
|
+
"GIT_AUTHOR_NAME",
|
|
7584
|
+
"GIT_AUTHOR_EMAIL",
|
|
7585
|
+
"GIT_COMMITTER_NAME",
|
|
7586
|
+
"GIT_COMMITTER_EMAIL",
|
|
7587
|
+
"SSH_AUTH_SOCK"
|
|
7588
|
+
]);
|
|
7174
7589
|
function ensureConnected(config) {
|
|
7175
7590
|
const agent = config.getAgent();
|
|
7176
7591
|
const diaryId = config.getDiaryId();
|
|
@@ -7184,303 +7599,548 @@ function ensureConnected(config) {
|
|
|
7184
7599
|
* Create all MoltNet tool definitions, ready to pass to `pi.registerTool()`.
|
|
7185
7600
|
*/
|
|
7186
7601
|
function createMoltNetTools(config) {
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
expandEntries: Type.Optional(Type.Boolean({ description: "Include full expanded entries" }))
|
|
7195
|
-
}),
|
|
7196
|
-
async execute(_id, params) {
|
|
7197
|
-
const { agent } = ensureConnected(config);
|
|
7198
|
-
const pack = await agent.packs.get(params.packId, { expand: params.expandEntries ? "entries" : void 0 });
|
|
7199
|
-
return {
|
|
7200
|
-
content: [{
|
|
7201
|
-
type: "text",
|
|
7202
|
-
text: JSON.stringify(pack, null, 2)
|
|
7203
|
-
}],
|
|
7204
|
-
details: {}
|
|
7205
|
-
};
|
|
7206
|
-
}
|
|
7602
|
+
const getPack = defineTool({
|
|
7603
|
+
name: "moltnet_pack_get",
|
|
7604
|
+
label: "Get MoltNet Pack",
|
|
7605
|
+
description: "Get a context pack by ID. Optionally expand included entries.",
|
|
7606
|
+
parameters: Type.Object({
|
|
7607
|
+
packId: Type.String({ description: "Context pack ID" }),
|
|
7608
|
+
expandEntries: Type.Optional(Type.Boolean({ description: "Include full expanded entries" }))
|
|
7207
7609
|
}),
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
type: "text",
|
|
7233
|
-
text: JSON.stringify(pack, null, 2)
|
|
7234
|
-
}],
|
|
7235
|
-
details: {}
|
|
7236
|
-
};
|
|
7237
|
-
}
|
|
7610
|
+
async execute(_id, params) {
|
|
7611
|
+
const { agent } = ensureConnected(config);
|
|
7612
|
+
const pack = await agent.packs.get(params.packId, { expand: params.expandEntries ? "entries" : void 0 });
|
|
7613
|
+
return {
|
|
7614
|
+
content: [{
|
|
7615
|
+
type: "text",
|
|
7616
|
+
text: JSON.stringify(pack, null, 2)
|
|
7617
|
+
}],
|
|
7618
|
+
details: {}
|
|
7619
|
+
};
|
|
7620
|
+
}
|
|
7621
|
+
});
|
|
7622
|
+
const createPack = defineTool({
|
|
7623
|
+
name: "moltnet_pack_create",
|
|
7624
|
+
label: "Create MoltNet Pack",
|
|
7625
|
+
description: "Persist a curated context pack. Entries are caller-ranked (lower rank = more prominent). Recipe/prompt/selection_rationale belong in params. Defaults to pinned=false — packs in the attribution pipeline are ephemeral unless the caller explicitly opts in.",
|
|
7626
|
+
parameters: Type.Object({
|
|
7627
|
+
entries: Type.Array(Type.Object({
|
|
7628
|
+
entryId: Type.String({ description: "Diary entry UUID" }),
|
|
7629
|
+
rank: Type.Number({ description: "Rank (1..N, lower = more prominent)" })
|
|
7630
|
+
}), { description: "Selected entries with their ranks" }),
|
|
7631
|
+
params: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Free-form recipe parameters (recipe name, prompt, selection rationale, etc.)" })),
|
|
7632
|
+
tokenBudget: Type.Optional(Type.Number({ description: "Soft token budget recorded on the pack (optional)" })),
|
|
7633
|
+
pinned: Type.Optional(Type.Boolean({ description: "Pin the pack against retention policy (default false)" }))
|
|
7238
7634
|
}),
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
})
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
}],
|
|
7266
|
-
details: {}
|
|
7267
|
-
};
|
|
7268
|
-
}
|
|
7635
|
+
async execute(_id, params) {
|
|
7636
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7637
|
+
const pack = await agent.packs.create(diaryId, {
|
|
7638
|
+
packType: "custom",
|
|
7639
|
+
params: params.params ?? {},
|
|
7640
|
+
entries: params.entries,
|
|
7641
|
+
tokenBudget: params.tokenBudget,
|
|
7642
|
+
pinned: params.pinned ?? false
|
|
7643
|
+
});
|
|
7644
|
+
return {
|
|
7645
|
+
content: [{
|
|
7646
|
+
type: "text",
|
|
7647
|
+
text: JSON.stringify(pack, null, 2)
|
|
7648
|
+
}],
|
|
7649
|
+
details: {}
|
|
7650
|
+
};
|
|
7651
|
+
}
|
|
7652
|
+
});
|
|
7653
|
+
const getPackProvenance = defineTool({
|
|
7654
|
+
name: "moltnet_pack_provenance",
|
|
7655
|
+
label: "Get MoltNet Pack Provenance",
|
|
7656
|
+
description: "Get the provenance graph for a context pack by ID or CID.",
|
|
7657
|
+
parameters: Type.Object({
|
|
7658
|
+
packId: Type.Optional(Type.String({ description: "Context pack ID" })),
|
|
7659
|
+
packCid: Type.Optional(Type.String({ description: "Context pack CID" })),
|
|
7660
|
+
depth: Type.Optional(Type.Number({ description: "Supersession ancestry depth to include (default 2)" }))
|
|
7269
7661
|
}),
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
}
|
|
7662
|
+
async execute(_id, params) {
|
|
7663
|
+
const { agent } = ensureConnected(config);
|
|
7664
|
+
if (!params.packId && !params.packCid) throw new Error("Provide either packId or packCid");
|
|
7665
|
+
if (params.packId && params.packCid) throw new Error("Provide only one of packId or packCid");
|
|
7666
|
+
const graph = params.packId ? await agent.packs.getProvenance(params.packId, { depth: params.depth ?? 2 }) : await agent.packs.getProvenanceByCid(params.packCid, { depth: params.depth ?? 2 });
|
|
7667
|
+
const payload = {
|
|
7668
|
+
metadata: graph.metadata,
|
|
7669
|
+
counts: {
|
|
7670
|
+
nodes: graph.nodes.length,
|
|
7671
|
+
edges: graph.edges.length
|
|
7672
|
+
},
|
|
7673
|
+
graph
|
|
7674
|
+
};
|
|
7675
|
+
return {
|
|
7676
|
+
content: [{
|
|
7677
|
+
type: "text",
|
|
7678
|
+
text: JSON.stringify(payload, null, 2)
|
|
7679
|
+
}],
|
|
7680
|
+
details: {}
|
|
7681
|
+
};
|
|
7682
|
+
}
|
|
7683
|
+
});
|
|
7684
|
+
const renderPack = defineTool({
|
|
7685
|
+
name: "moltnet_pack_render",
|
|
7686
|
+
label: "Render MoltNet Pack",
|
|
7687
|
+
description: "Fetch a pack with entries, transform it into docs, then preview or persist the rendered pack.",
|
|
7688
|
+
parameters: Type.Object({
|
|
7689
|
+
packId: Type.String({ description: "Context pack ID" }),
|
|
7690
|
+
renderMethod: Type.Optional(Type.String({ description: "Render method label. Defaults to pi:pack-to-docs-v1" })),
|
|
7691
|
+
markdown: Type.Optional(Type.String({ description: "Optional caller-authored markdown override" })),
|
|
7692
|
+
preview: Type.Optional(Type.Boolean({ description: "Preview without persisting (default false)" })),
|
|
7693
|
+
pinned: Type.Optional(Type.Boolean({ description: "Persist the rendered pack as pinned (default false)" }))
|
|
7302
7694
|
}),
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
renderMethod
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
}
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7695
|
+
async execute(_id, params) {
|
|
7696
|
+
const { agent } = ensureConnected(config);
|
|
7697
|
+
const renderMethod = params.renderMethod ?? "pi:pack-to-docs-v1";
|
|
7698
|
+
let renderedMarkdown = params.markdown;
|
|
7699
|
+
if (!renderedMarkdown && !renderMethod.startsWith("server:")) renderedMarkdown = renderPhase6Markdown(await agent.packs.get(params.packId, { expand: "entries" }));
|
|
7700
|
+
const result = params.preview ?? false ? await agent.packs.previewRendered(params.packId, {
|
|
7701
|
+
renderMethod,
|
|
7702
|
+
renderedMarkdown
|
|
7703
|
+
}) : await agent.packs.render(params.packId, {
|
|
7704
|
+
renderMethod,
|
|
7705
|
+
renderedMarkdown,
|
|
7706
|
+
pinned: params.pinned
|
|
7707
|
+
});
|
|
7708
|
+
return {
|
|
7709
|
+
content: [{
|
|
7710
|
+
type: "text",
|
|
7711
|
+
text: JSON.stringify(result, null, 2)
|
|
7712
|
+
}],
|
|
7713
|
+
details: {}
|
|
7714
|
+
};
|
|
7715
|
+
}
|
|
7716
|
+
});
|
|
7717
|
+
const listRenderedPacks = defineTool({
|
|
7718
|
+
name: "moltnet_rendered_pack_list",
|
|
7719
|
+
label: "List MoltNet Rendered Packs",
|
|
7720
|
+
description: "List rendered packs for the current MoltNet diary, optionally filtered by source pack or render method.",
|
|
7721
|
+
parameters: Type.Object({
|
|
7722
|
+
sourcePackId: Type.Optional(Type.String({ description: "Filter by source pack ID" })),
|
|
7723
|
+
renderMethod: Type.Optional(Type.String({ description: "Filter by render method" })),
|
|
7724
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 10)" })),
|
|
7725
|
+
offset: Type.Optional(Type.Number({ description: "Offset for pagination (default 0)" }))
|
|
7329
7726
|
}),
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7727
|
+
async execute(_id, params) {
|
|
7728
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7729
|
+
const rendered = await agent.packs.listRendered(diaryId, {
|
|
7730
|
+
sourcePackId: params.sourcePackId,
|
|
7731
|
+
renderMethod: params.renderMethod,
|
|
7732
|
+
limit: params.limit ?? 10,
|
|
7733
|
+
offset: params.offset ?? 0
|
|
7734
|
+
});
|
|
7735
|
+
return {
|
|
7736
|
+
content: [{
|
|
7737
|
+
type: "text",
|
|
7738
|
+
text: JSON.stringify(rendered, null, 2)
|
|
7739
|
+
}],
|
|
7740
|
+
details: {}
|
|
7741
|
+
};
|
|
7742
|
+
}
|
|
7743
|
+
});
|
|
7744
|
+
const getRenderedPack = defineTool({
|
|
7745
|
+
name: "moltnet_rendered_pack_get",
|
|
7746
|
+
label: "Get MoltNet Rendered Pack",
|
|
7747
|
+
description: "Get a rendered pack by ID.",
|
|
7748
|
+
parameters: Type.Object({ renderedPackId: Type.String({ description: "Rendered pack ID" }) }),
|
|
7749
|
+
async execute(_id, params) {
|
|
7750
|
+
const { agent } = ensureConnected(config);
|
|
7751
|
+
const rendered = await agent.packs.getRendered(params.renderedPackId);
|
|
7752
|
+
return {
|
|
7753
|
+
content: [{
|
|
7754
|
+
type: "text",
|
|
7755
|
+
text: JSON.stringify(rendered, null, 2)
|
|
7756
|
+
}],
|
|
7757
|
+
details: {}
|
|
7758
|
+
};
|
|
7759
|
+
}
|
|
7760
|
+
});
|
|
7761
|
+
const verifyRenderedPack = defineTool({
|
|
7762
|
+
name: "moltnet_rendered_pack_verify",
|
|
7763
|
+
label: "Verify MoltNet Rendered Pack",
|
|
7764
|
+
description: "Create a verification workflow for a rendered pack and return the verification ID and nonce.",
|
|
7765
|
+
parameters: Type.Object({
|
|
7766
|
+
renderedPackId: Type.String({ description: "Rendered pack ID" }),
|
|
7767
|
+
nonce: Type.Optional(Type.String({ description: "Caller-supplied idempotency nonce. Generated automatically if omitted." }))
|
|
7768
|
+
}),
|
|
7769
|
+
async execute(_id, params) {
|
|
7770
|
+
const { agent } = ensureConnected(config);
|
|
7771
|
+
const nonce = params.nonce ?? randomUUID();
|
|
7772
|
+
const verification = await agent.packs.verifyRendered(params.renderedPackId, { nonce });
|
|
7773
|
+
return {
|
|
7774
|
+
content: [{
|
|
7775
|
+
type: "text",
|
|
7776
|
+
text: JSON.stringify({
|
|
7777
|
+
...verification,
|
|
7778
|
+
nonce
|
|
7779
|
+
}, null, 2)
|
|
7780
|
+
}],
|
|
7781
|
+
details: {}
|
|
7782
|
+
};
|
|
7783
|
+
}
|
|
7784
|
+
});
|
|
7785
|
+
const judgeRenderedPack = defineTool({
|
|
7786
|
+
name: "moltnet_rendered_pack_judge",
|
|
7787
|
+
label: "Judge MoltNet Rendered Pack",
|
|
7788
|
+
description: "Run the fidelity judge against a rendered pack. Local mode (no nonce): fetch the rendered pack + its source pack with entries, judge locally, return scores. Proctored mode (nonce): claim the verification payload from the API, judge, and submit scores with a Pi judge-recipe CID.",
|
|
7789
|
+
parameters: Type.Object({
|
|
7790
|
+
renderedPackId: Type.String({ description: "Rendered pack ID" }),
|
|
7791
|
+
nonce: Type.Optional(Type.String({ description: "Verification nonce from moltnet_rendered_pack_verify. If set, runs proctored mode and submits scores. If omitted, runs local mode and does not submit." })),
|
|
7792
|
+
rubric: Type.Optional(Type.String({ description: "Custom rubric override (local mode only). Defaults to the built-in rubric when omitted." }))
|
|
7793
|
+
}),
|
|
7794
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
7795
|
+
const { agent } = ensureConnected(config);
|
|
7796
|
+
const model = ctx?.model;
|
|
7797
|
+
if (!model) throw new Error("No active model in pi session — cannot run the fidelity judge.");
|
|
7798
|
+
let sourceEntriesMd;
|
|
7799
|
+
let renderedContent;
|
|
7800
|
+
let rubric;
|
|
7801
|
+
if (params.nonce) {
|
|
7802
|
+
if (params.rubric) throw new Error("`rubric` is only supported in local mode (omit `nonce`).");
|
|
7803
|
+
const claim = await agent.packs.claimVerification(params.renderedPackId);
|
|
7804
|
+
sourceEntriesMd = buildSourceEntriesMarkdown(claim.sourceEntries);
|
|
7805
|
+
renderedContent = claim.renderedContent;
|
|
7806
|
+
rubric = claim.rubric?.trim() ? claim.rubric : DEFAULT_RUBRIC;
|
|
7807
|
+
} else {
|
|
7337
7808
|
const rendered = await agent.packs.getRendered(params.renderedPackId);
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
};
|
|
7809
|
+
if (!rendered.content?.trim()) throw new Error(`rendered pack ${params.renderedPackId} has empty content`);
|
|
7810
|
+
const sourcePack = await agent.packs.get(rendered.sourcePackId, { expand: "entries" });
|
|
7811
|
+
if (!sourcePack.entries || sourcePack.entries.length === 0) throw new Error(`source pack ${rendered.sourcePackId} has no entries`);
|
|
7812
|
+
sourceEntriesMd = buildSourceEntriesMarkdown(sourcePack.entries.map((entry) => ({
|
|
7813
|
+
title: entry.entry.title,
|
|
7814
|
+
content: entry.entry.content
|
|
7815
|
+
})));
|
|
7816
|
+
renderedContent = rendered.content;
|
|
7817
|
+
rubric = params.rubric?.trim() ? params.rubric : DEFAULT_RUBRIC;
|
|
7818
|
+
}
|
|
7819
|
+
let scores;
|
|
7820
|
+
try {
|
|
7821
|
+
scores = await runFidelityJudge({
|
|
7822
|
+
model,
|
|
7823
|
+
sourceEntries: sourceEntriesMd,
|
|
7824
|
+
renderedContent,
|
|
7825
|
+
rubric
|
|
7826
|
+
});
|
|
7827
|
+
} catch (err) {
|
|
7828
|
+
throw new Error(`judge failed: ${err.message ?? String(err)}`);
|
|
7345
7829
|
}
|
|
7830
|
+
if (!params.nonce) return {
|
|
7831
|
+
content: [{
|
|
7832
|
+
type: "text",
|
|
7833
|
+
text: JSON.stringify({
|
|
7834
|
+
mode: "local",
|
|
7835
|
+
renderedPackId: params.renderedPackId,
|
|
7836
|
+
scores
|
|
7837
|
+
}, null, 2)
|
|
7838
|
+
}],
|
|
7839
|
+
details: {}
|
|
7840
|
+
};
|
|
7841
|
+
const recipe = computePiJudgeRecipeCid({
|
|
7842
|
+
judgePrompt: JUDGE_SYSTEM_PROMPT,
|
|
7843
|
+
rubric,
|
|
7844
|
+
promptAsset: JUDGE_PROMPT_ASSET_PATH,
|
|
7845
|
+
rubricAsset: RUBRIC_ASSET_PATH
|
|
7846
|
+
});
|
|
7847
|
+
const providerName = model.provider ?? "pi";
|
|
7848
|
+
const modelId = model.id ?? "unknown";
|
|
7849
|
+
const submit = await agent.packs.submitVerification(params.renderedPackId, {
|
|
7850
|
+
nonce: params.nonce,
|
|
7851
|
+
coverage: scores.coverage,
|
|
7852
|
+
grounding: scores.grounding,
|
|
7853
|
+
faithfulness: scores.faithfulness,
|
|
7854
|
+
transcript: scores.reasoning,
|
|
7855
|
+
judgeModel: modelId,
|
|
7856
|
+
judgeProvider: providerName,
|
|
7857
|
+
judgeBinaryCid: recipe.cid
|
|
7858
|
+
});
|
|
7859
|
+
return {
|
|
7860
|
+
content: [{
|
|
7861
|
+
type: "text",
|
|
7862
|
+
text: JSON.stringify({
|
|
7863
|
+
mode: "proctored",
|
|
7864
|
+
renderedPackId: params.renderedPackId,
|
|
7865
|
+
scores,
|
|
7866
|
+
submission: submit,
|
|
7867
|
+
judgeRecipeCid: recipe.cid,
|
|
7868
|
+
judgeRecipeManifest: recipe.manifest
|
|
7869
|
+
}, null, 2)
|
|
7870
|
+
}],
|
|
7871
|
+
details: {}
|
|
7872
|
+
};
|
|
7873
|
+
}
|
|
7874
|
+
});
|
|
7875
|
+
const diaryTags = defineTool({
|
|
7876
|
+
name: "moltnet_diary_tags",
|
|
7877
|
+
label: "List MoltNet Diary Tags",
|
|
7878
|
+
description: "Inventory tags on the current diary with entry counts. Cheap reconnaissance before committing to a search or list — use it to discover scope prefixes and cluster sizes. Optional prefix/minCount/entryTypes filters narrow the result.",
|
|
7879
|
+
parameters: Type.Object({
|
|
7880
|
+
prefix: Type.Optional(Type.String({ description: "Filter to tags starting with this prefix (e.g. \"scope:\")" })),
|
|
7881
|
+
minCount: Type.Optional(Type.Number({ description: "Exclude tags with fewer than this many entries" })),
|
|
7882
|
+
entryTypes: Type.Optional(Type.Array(Type.Union([
|
|
7883
|
+
Type.Literal("episodic"),
|
|
7884
|
+
Type.Literal("semantic"),
|
|
7885
|
+
Type.Literal("procedural"),
|
|
7886
|
+
Type.Literal("reflection"),
|
|
7887
|
+
Type.Literal("identity"),
|
|
7888
|
+
Type.Literal("soul")
|
|
7889
|
+
]), { description: "Scope the tag count to these entry types" }))
|
|
7346
7890
|
}),
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7891
|
+
async execute(_id, params) {
|
|
7892
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7893
|
+
const result = await agent.diaries.tags(diaryId, {
|
|
7894
|
+
prefix: params.prefix,
|
|
7895
|
+
minCount: params.minCount,
|
|
7896
|
+
entryTypes: params.entryTypes
|
|
7897
|
+
});
|
|
7898
|
+
return {
|
|
7899
|
+
content: [{
|
|
7900
|
+
type: "text",
|
|
7901
|
+
text: JSON.stringify(result, null, 2)
|
|
7902
|
+
}],
|
|
7903
|
+
details: {}
|
|
7904
|
+
};
|
|
7905
|
+
}
|
|
7906
|
+
});
|
|
7907
|
+
const listEntries = defineTool({
|
|
7908
|
+
name: "moltnet_list_entries",
|
|
7909
|
+
label: "List MoltNet Diary Entries",
|
|
7910
|
+
description: "List entries from the MoltNet diary. When `entryIds` is provided, batch-fetches those specific entries (max 50) and returns full fields including entryType, contentSignature, and contentHash for signature checks. Otherwise returns recent entries with a content preview.",
|
|
7911
|
+
parameters: Type.Object({
|
|
7912
|
+
limit: Type.Optional(Type.Number({ description: "Max entries to return (default 10)" })),
|
|
7913
|
+
tag: Type.Optional(Type.String({ description: "Filter by tag (optional)" })),
|
|
7914
|
+
entryIds: Type.Optional(Type.Array(Type.String(), {
|
|
7915
|
+
description: "Batch-fetch specific entries by UUID (max 50). Overrides `limit` and `tag` for selection.",
|
|
7916
|
+
maxItems: 50
|
|
7917
|
+
}))
|
|
7918
|
+
}),
|
|
7919
|
+
async execute(_id, params) {
|
|
7920
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7921
|
+
const query = {
|
|
7922
|
+
orderBy: "createdAt",
|
|
7923
|
+
order: "desc"
|
|
7924
|
+
};
|
|
7925
|
+
const batchMode = !!params.entryIds?.length;
|
|
7926
|
+
if (batchMode) query.ids = params.entryIds;
|
|
7927
|
+
else {
|
|
7928
|
+
query.limit = params.limit ?? 10;
|
|
7929
|
+
if (params.tag) query.tag = params.tag;
|
|
7369
7930
|
}
|
|
7931
|
+
const entries = await agent.entries.list(diaryId, query);
|
|
7932
|
+
return {
|
|
7933
|
+
content: [{
|
|
7934
|
+
type: "text",
|
|
7935
|
+
text: JSON.stringify(entries.items?.map((e) => batchMode ? {
|
|
7936
|
+
id: e.id,
|
|
7937
|
+
title: e.title,
|
|
7938
|
+
entryType: e.entryType,
|
|
7939
|
+
tags: e.tags,
|
|
7940
|
+
importance: e.importance,
|
|
7941
|
+
contentHash: e.contentHash,
|
|
7942
|
+
contentSignature: e.contentSignature,
|
|
7943
|
+
signingNonce: e.signingNonce,
|
|
7944
|
+
createdAt: e.createdAt
|
|
7945
|
+
} : {
|
|
7946
|
+
id: e.id,
|
|
7947
|
+
title: e.title,
|
|
7948
|
+
tags: e.tags,
|
|
7949
|
+
importance: e.importance,
|
|
7950
|
+
createdAt: e.createdAt,
|
|
7951
|
+
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
7952
|
+
}), null, 2)
|
|
7953
|
+
}],
|
|
7954
|
+
details: {}
|
|
7955
|
+
};
|
|
7956
|
+
}
|
|
7957
|
+
});
|
|
7958
|
+
const getEntry = defineTool({
|
|
7959
|
+
name: "moltnet_get_entry",
|
|
7960
|
+
label: "Get MoltNet Diary Entry",
|
|
7961
|
+
description: "Get the full content of a specific diary entry by ID.",
|
|
7962
|
+
parameters: Type.Object({ entryId: Type.String({ description: "The entry ID to fetch" }) }),
|
|
7963
|
+
async execute(_id, params) {
|
|
7964
|
+
const { agent } = ensureConnected(config);
|
|
7965
|
+
const entry = await agent.entries.get(params.entryId);
|
|
7966
|
+
return {
|
|
7967
|
+
content: [{
|
|
7968
|
+
type: "text",
|
|
7969
|
+
text: JSON.stringify({
|
|
7970
|
+
id: entry.id,
|
|
7971
|
+
title: entry.title,
|
|
7972
|
+
content: entry.content,
|
|
7973
|
+
tags: entry.tags,
|
|
7974
|
+
importance: entry.importance,
|
|
7975
|
+
createdAt: entry.createdAt
|
|
7976
|
+
}, null, 2)
|
|
7977
|
+
}],
|
|
7978
|
+
details: {}
|
|
7979
|
+
};
|
|
7980
|
+
}
|
|
7981
|
+
});
|
|
7982
|
+
const searchEntries = defineTool({
|
|
7983
|
+
name: "moltnet_search_entries",
|
|
7984
|
+
label: "Search MoltNet Diary Entries",
|
|
7985
|
+
description: "Search diary entries by semantic query. Uses vector similarity to find relevant entries.",
|
|
7986
|
+
parameters: Type.Object({
|
|
7987
|
+
query: Type.String({ description: "Natural language search query" }),
|
|
7988
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 5)" }))
|
|
7370
7989
|
}),
|
|
7990
|
+
async execute(_id, params) {
|
|
7991
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7992
|
+
const results = await agent.entries.search({
|
|
7993
|
+
diaryId,
|
|
7994
|
+
query: params.query,
|
|
7995
|
+
limit: params.limit ?? 5
|
|
7996
|
+
});
|
|
7997
|
+
return {
|
|
7998
|
+
content: [{
|
|
7999
|
+
type: "text",
|
|
8000
|
+
text: JSON.stringify(results.results?.map((e) => ({
|
|
8001
|
+
id: e.id,
|
|
8002
|
+
title: e.title,
|
|
8003
|
+
tags: e.tags,
|
|
8004
|
+
importance: e.importance,
|
|
8005
|
+
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
8006
|
+
})), null, 2)
|
|
8007
|
+
}],
|
|
8008
|
+
details: {}
|
|
8009
|
+
};
|
|
8010
|
+
}
|
|
8011
|
+
});
|
|
8012
|
+
const createEntry = defineTool({
|
|
8013
|
+
name: "moltnet_create_entry",
|
|
8014
|
+
label: "Create MoltNet Diary Entry",
|
|
8015
|
+
description: "Create a new diary entry to record decisions, findings, incidents, or reflections.",
|
|
8016
|
+
parameters: Type.Object({
|
|
8017
|
+
title: Type.String({ description: "Entry title (concise, descriptive)" }),
|
|
8018
|
+
content: Type.String({ description: "Entry content (markdown)" }),
|
|
8019
|
+
tags: Type.Optional(Type.Array(Type.String(), { description: "Tags for categorization" })),
|
|
8020
|
+
importance: Type.Optional(Type.Number({ description: "Importance 1-10 (default 5)" }))
|
|
8021
|
+
}),
|
|
8022
|
+
async execute(_id, params) {
|
|
8023
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
8024
|
+
const entry = await agent.entries.create(diaryId, {
|
|
8025
|
+
title: params.title,
|
|
8026
|
+
content: params.content,
|
|
8027
|
+
tags: params.tags ?? [],
|
|
8028
|
+
importance: params.importance ?? 5
|
|
8029
|
+
});
|
|
8030
|
+
return {
|
|
8031
|
+
content: [{
|
|
8032
|
+
type: "text",
|
|
8033
|
+
text: JSON.stringify({
|
|
8034
|
+
id: entry.id,
|
|
8035
|
+
title: entry.title,
|
|
8036
|
+
createdAt: entry.createdAt
|
|
8037
|
+
}, null, 2)
|
|
8038
|
+
}],
|
|
8039
|
+
details: {}
|
|
8040
|
+
};
|
|
8041
|
+
}
|
|
8042
|
+
});
|
|
8043
|
+
const reviewSessionErrors = defineTool({
|
|
8044
|
+
name: "moltnet_review_session_errors",
|
|
8045
|
+
label: "Review Session Tool Errors",
|
|
8046
|
+
description: "Review tool failures buffered during this session (isError=true results). Use this to decide whether any failures are worth persisting as a diary entry via moltnet_create_entry. Most failures are transient (denied prompts, empty greps, mid-iteration typecheck errors) and should NOT be written to the diary — only persist incidents that represent a real finding (root cause identified, non-obvious workaround, recurring pattern). Pass clear=true to drop the buffer after reviewing.",
|
|
8047
|
+
parameters: Type.Object({ clear: Type.Optional(Type.Boolean({ description: "If true, empty the buffer after returning it. Use once you have decided whether to persist." })) }),
|
|
8048
|
+
async execute(_id, params) {
|
|
8049
|
+
const errors = config.getSessionErrors();
|
|
8050
|
+
const payload = {
|
|
8051
|
+
count: errors.length,
|
|
8052
|
+
errors: errors.map((e) => ({
|
|
8053
|
+
toolName: e.toolName,
|
|
8054
|
+
toolCallId: e.toolCallId,
|
|
8055
|
+
timestamp: new Date(e.timestamp).toISOString(),
|
|
8056
|
+
input: e.input,
|
|
8057
|
+
error: e.error
|
|
8058
|
+
}))
|
|
8059
|
+
};
|
|
8060
|
+
if (params.clear) config.clearSessionErrors();
|
|
8061
|
+
return {
|
|
8062
|
+
content: [{
|
|
8063
|
+
type: "text",
|
|
8064
|
+
text: JSON.stringify(payload, null, 2)
|
|
8065
|
+
}],
|
|
8066
|
+
details: {}
|
|
8067
|
+
};
|
|
8068
|
+
}
|
|
8069
|
+
});
|
|
8070
|
+
const HOST_EXEC_ALLOWED = new Set([
|
|
8071
|
+
"git",
|
|
8072
|
+
"gh",
|
|
8073
|
+
"moltnet"
|
|
8074
|
+
]);
|
|
8075
|
+
const hostExecBaseEnv = config.hostExecBaseEnv ?? HOST_EXEC_DEFAULT_BASE_ENV;
|
|
8076
|
+
const HOST_EXEC_TIMEOUT_MS = 6e4;
|
|
8077
|
+
return [
|
|
8078
|
+
getPack,
|
|
8079
|
+
createPack,
|
|
8080
|
+
getPackProvenance,
|
|
8081
|
+
renderPack,
|
|
8082
|
+
listRenderedPacks,
|
|
8083
|
+
getRenderedPack,
|
|
8084
|
+
verifyRenderedPack,
|
|
8085
|
+
judgeRenderedPack,
|
|
8086
|
+
diaryTags,
|
|
8087
|
+
listEntries,
|
|
8088
|
+
getEntry,
|
|
8089
|
+
searchEntries,
|
|
8090
|
+
createEntry,
|
|
8091
|
+
reviewSessionErrors,
|
|
7371
8092
|
defineTool({
|
|
7372
|
-
name: "
|
|
7373
|
-
label: "
|
|
7374
|
-
description: "
|
|
8093
|
+
name: "moltnet_host_exec",
|
|
8094
|
+
label: "Run command on host (escape hatch — requires user approval)",
|
|
8095
|
+
description: "Runs a command on the HOST machine, outside the sandbox VM. The user will be prompted to approve each invocation via a UI dialog — do NOT call this tool speculatively. Use ONLY when a sandboxed operation is impossible — e.g. `git push`, `gh pr create`.\n\nAllowed executables: git, gh, moltnet. Runs with a minimal env (PATH, HOME, GIT_CONFIG_GLOBAL, …); pass any additional vars via the `env` parameter (e.g. GH_TOKEN). Every invocation is logged as an auditable host execution.",
|
|
7375
8096
|
parameters: Type.Object({
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
8097
|
+
executable: Type.String({ description: "Executable to run (git | gh | moltnet)" }),
|
|
8098
|
+
args: Type.Array(Type.String(), { description: "Arguments to pass to the executable" }),
|
|
8099
|
+
env: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "Additional environment variables for this invocation (e.g. { \"GH_TOKEN\": \"...\" }). Merged on top of the minimal base env." }))
|
|
7379
8100
|
}),
|
|
7380
8101
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
const
|
|
7390
|
-
|
|
7391
|
-
renderedContent = claim.renderedContent;
|
|
7392
|
-
rubric = claim.rubric?.trim() ? claim.rubric : DEFAULT_RUBRIC;
|
|
7393
|
-
} else {
|
|
7394
|
-
const rendered = await agent.packs.getRendered(params.renderedPackId);
|
|
7395
|
-
if (!rendered.content?.trim()) throw new Error(`rendered pack ${params.renderedPackId} has empty content`);
|
|
7396
|
-
const sourcePack = await agent.packs.get(rendered.sourcePackId, { expand: "entries" });
|
|
7397
|
-
if (!sourcePack.entries || sourcePack.entries.length === 0) throw new Error(`source pack ${rendered.sourcePackId} has no entries`);
|
|
7398
|
-
sourceEntriesMd = buildSourceEntriesMarkdown(sourcePack.entries.map((entry) => ({
|
|
7399
|
-
title: entry.entry.title,
|
|
7400
|
-
content: entry.entry.content
|
|
7401
|
-
})));
|
|
7402
|
-
renderedContent = rendered.content;
|
|
7403
|
-
rubric = params.rubric?.trim() ? params.rubric : DEFAULT_RUBRIC;
|
|
8102
|
+
if (!HOST_EXEC_ALLOWED.has(params.executable)) throw new Error(`host_exec: '${params.executable}' is not in the allowed list (${[...HOST_EXEC_ALLOWED].join(", ")}). Extend HOST_EXEC_ALLOWED only after explicit security review.`);
|
|
8103
|
+
if (ctx?.ui) {
|
|
8104
|
+
const cmdDisplay = [params.executable, ...params.args].join(" ");
|
|
8105
|
+
if (!await ctx.ui.confirm("Allow host command?", `The agent wants to run on your machine:\n\n ${cmdDisplay}\n\nAllow?`)) throw new Error(`host_exec: user declined approval for: ${cmdDisplay}`);
|
|
8106
|
+
}
|
|
8107
|
+
const cwd = config.getHostCwd?.() ?? process.cwd();
|
|
8108
|
+
const baseEnv = {};
|
|
8109
|
+
for (const key of hostExecBaseEnv) {
|
|
8110
|
+
const val = process.env[key];
|
|
8111
|
+
if (val !== void 0) baseEnv[key] = val;
|
|
7404
8112
|
}
|
|
7405
|
-
|
|
8113
|
+
const mergedEnv = {
|
|
8114
|
+
...baseEnv,
|
|
8115
|
+
...params.env ?? {}
|
|
8116
|
+
};
|
|
8117
|
+
let stdout;
|
|
8118
|
+
let stderr = "";
|
|
7406
8119
|
try {
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
8120
|
+
stdout = execFileSync(params.executable, params.args, {
|
|
8121
|
+
encoding: "utf8",
|
|
8122
|
+
cwd,
|
|
8123
|
+
env: mergedEnv,
|
|
8124
|
+
stdio: [
|
|
8125
|
+
"pipe",
|
|
8126
|
+
"pipe",
|
|
8127
|
+
"pipe"
|
|
8128
|
+
],
|
|
8129
|
+
timeout: HOST_EXEC_TIMEOUT_MS
|
|
7412
8130
|
});
|
|
7413
8131
|
} catch (err) {
|
|
7414
|
-
|
|
8132
|
+
const e = err;
|
|
8133
|
+
stdout = e.stdout ?? "";
|
|
8134
|
+
stderr = e.stderr ?? e.message ?? String(err);
|
|
7415
8135
|
}
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
}, null, 2)
|
|
7424
|
-
}],
|
|
7425
|
-
details: {}
|
|
7426
|
-
};
|
|
7427
|
-
const recipe = computePiJudgeRecipeCid({
|
|
7428
|
-
judgePrompt: JUDGE_SYSTEM_PROMPT,
|
|
7429
|
-
rubric,
|
|
7430
|
-
promptAsset: JUDGE_PROMPT_ASSET_PATH,
|
|
7431
|
-
rubricAsset: RUBRIC_ASSET_PATH
|
|
7432
|
-
});
|
|
7433
|
-
const providerName = model.provider ?? "pi";
|
|
7434
|
-
const modelId = model.id ?? "unknown";
|
|
7435
|
-
const submit = await agent.packs.submitVerification(params.renderedPackId, {
|
|
7436
|
-
nonce: params.nonce,
|
|
7437
|
-
coverage: scores.coverage,
|
|
7438
|
-
grounding: scores.grounding,
|
|
7439
|
-
faithfulness: scores.faithfulness,
|
|
7440
|
-
transcript: scores.reasoning,
|
|
7441
|
-
judgeModel: modelId,
|
|
7442
|
-
judgeProvider: providerName,
|
|
7443
|
-
judgeBinaryCid: recipe.cid
|
|
7444
|
-
});
|
|
7445
|
-
return {
|
|
7446
|
-
content: [{
|
|
7447
|
-
type: "text",
|
|
7448
|
-
text: JSON.stringify({
|
|
7449
|
-
mode: "proctored",
|
|
7450
|
-
renderedPackId: params.renderedPackId,
|
|
7451
|
-
scores,
|
|
7452
|
-
submission: submit,
|
|
7453
|
-
judgeRecipeCid: recipe.cid,
|
|
7454
|
-
judgeRecipeManifest: recipe.manifest
|
|
7455
|
-
}, null, 2)
|
|
7456
|
-
}],
|
|
7457
|
-
details: {}
|
|
8136
|
+
const result = {
|
|
8137
|
+
host_exec: true,
|
|
8138
|
+
executable: params.executable,
|
|
8139
|
+
args: params.args,
|
|
8140
|
+
cwd,
|
|
8141
|
+
stdout: stdout.trimEnd(),
|
|
8142
|
+
stderr: stderr.trimEnd() || void 0
|
|
7458
8143
|
};
|
|
7459
|
-
}
|
|
7460
|
-
}),
|
|
7461
|
-
defineTool({
|
|
7462
|
-
name: "moltnet_diary_tags",
|
|
7463
|
-
label: "List MoltNet Diary Tags",
|
|
7464
|
-
description: "Inventory tags on the current diary with entry counts. Cheap reconnaissance before committing to a search or list — use it to discover scope prefixes and cluster sizes. Optional prefix/minCount/entryTypes filters narrow the result.",
|
|
7465
|
-
parameters: Type.Object({
|
|
7466
|
-
prefix: Type.Optional(Type.String({ description: "Filter to tags starting with this prefix (e.g. \"scope:\")" })),
|
|
7467
|
-
minCount: Type.Optional(Type.Number({ description: "Exclude tags with fewer than this many entries" })),
|
|
7468
|
-
entryTypes: Type.Optional(Type.Array(Type.Union([
|
|
7469
|
-
Type.Literal("episodic"),
|
|
7470
|
-
Type.Literal("semantic"),
|
|
7471
|
-
Type.Literal("procedural"),
|
|
7472
|
-
Type.Literal("reflection"),
|
|
7473
|
-
Type.Literal("identity"),
|
|
7474
|
-
Type.Literal("soul")
|
|
7475
|
-
]), { description: "Scope the tag count to these entry types" }))
|
|
7476
|
-
}),
|
|
7477
|
-
async execute(_id, params) {
|
|
7478
|
-
const { agent, diaryId } = ensureConnected(config);
|
|
7479
|
-
const result = await agent.diaries.tags(diaryId, {
|
|
7480
|
-
prefix: params.prefix,
|
|
7481
|
-
minCount: params.minCount,
|
|
7482
|
-
entryTypes: params.entryTypes
|
|
7483
|
-
});
|
|
7484
8144
|
return {
|
|
7485
8145
|
content: [{
|
|
7486
8146
|
type: "text",
|
|
@@ -7489,169 +8149,6 @@ function createMoltNetTools(config) {
|
|
|
7489
8149
|
details: {}
|
|
7490
8150
|
};
|
|
7491
8151
|
}
|
|
7492
|
-
}),
|
|
7493
|
-
defineTool({
|
|
7494
|
-
name: "moltnet_list_entries",
|
|
7495
|
-
label: "List MoltNet Diary Entries",
|
|
7496
|
-
description: "List entries from the MoltNet diary. When `entryIds` is provided, batch-fetches those specific entries (max 50) and returns full fields including entryType, contentSignature, and contentHash for signature checks. Otherwise returns recent entries with a content preview.",
|
|
7497
|
-
parameters: Type.Object({
|
|
7498
|
-
limit: Type.Optional(Type.Number({ description: "Max entries to return (default 10)" })),
|
|
7499
|
-
tag: Type.Optional(Type.String({ description: "Filter by tag (optional)" })),
|
|
7500
|
-
entryIds: Type.Optional(Type.Array(Type.String(), {
|
|
7501
|
-
description: "Batch-fetch specific entries by UUID (max 50). Overrides `limit` and `tag` for selection.",
|
|
7502
|
-
maxItems: 50
|
|
7503
|
-
}))
|
|
7504
|
-
}),
|
|
7505
|
-
async execute(_id, params) {
|
|
7506
|
-
const { agent, diaryId } = ensureConnected(config);
|
|
7507
|
-
const query = {
|
|
7508
|
-
orderBy: "createdAt",
|
|
7509
|
-
order: "desc"
|
|
7510
|
-
};
|
|
7511
|
-
const batchMode = !!params.entryIds?.length;
|
|
7512
|
-
if (batchMode) query.ids = params.entryIds;
|
|
7513
|
-
else {
|
|
7514
|
-
query.limit = params.limit ?? 10;
|
|
7515
|
-
if (params.tag) query.tag = params.tag;
|
|
7516
|
-
}
|
|
7517
|
-
const entries = await agent.entries.list(diaryId, query);
|
|
7518
|
-
return {
|
|
7519
|
-
content: [{
|
|
7520
|
-
type: "text",
|
|
7521
|
-
text: JSON.stringify(entries.items?.map((e) => batchMode ? {
|
|
7522
|
-
id: e.id,
|
|
7523
|
-
title: e.title,
|
|
7524
|
-
entryType: e.entryType,
|
|
7525
|
-
tags: e.tags,
|
|
7526
|
-
importance: e.importance,
|
|
7527
|
-
contentHash: e.contentHash,
|
|
7528
|
-
contentSignature: e.contentSignature,
|
|
7529
|
-
signingNonce: e.signingNonce,
|
|
7530
|
-
createdAt: e.createdAt
|
|
7531
|
-
} : {
|
|
7532
|
-
id: e.id,
|
|
7533
|
-
title: e.title,
|
|
7534
|
-
tags: e.tags,
|
|
7535
|
-
importance: e.importance,
|
|
7536
|
-
createdAt: e.createdAt,
|
|
7537
|
-
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
7538
|
-
}), null, 2)
|
|
7539
|
-
}],
|
|
7540
|
-
details: {}
|
|
7541
|
-
};
|
|
7542
|
-
}
|
|
7543
|
-
}),
|
|
7544
|
-
defineTool({
|
|
7545
|
-
name: "moltnet_get_entry",
|
|
7546
|
-
label: "Get MoltNet Diary Entry",
|
|
7547
|
-
description: "Get the full content of a specific diary entry by ID.",
|
|
7548
|
-
parameters: Type.Object({ entryId: Type.String({ description: "The entry ID to fetch" }) }),
|
|
7549
|
-
async execute(_id, params) {
|
|
7550
|
-
const { agent } = ensureConnected(config);
|
|
7551
|
-
const entry = await agent.entries.get(params.entryId);
|
|
7552
|
-
return {
|
|
7553
|
-
content: [{
|
|
7554
|
-
type: "text",
|
|
7555
|
-
text: JSON.stringify({
|
|
7556
|
-
id: entry.id,
|
|
7557
|
-
title: entry.title,
|
|
7558
|
-
content: entry.content,
|
|
7559
|
-
tags: entry.tags,
|
|
7560
|
-
importance: entry.importance,
|
|
7561
|
-
createdAt: entry.createdAt
|
|
7562
|
-
}, null, 2)
|
|
7563
|
-
}],
|
|
7564
|
-
details: {}
|
|
7565
|
-
};
|
|
7566
|
-
}
|
|
7567
|
-
}),
|
|
7568
|
-
defineTool({
|
|
7569
|
-
name: "moltnet_search_entries",
|
|
7570
|
-
label: "Search MoltNet Diary Entries",
|
|
7571
|
-
description: "Search diary entries by semantic query. Uses vector similarity to find relevant entries.",
|
|
7572
|
-
parameters: Type.Object({
|
|
7573
|
-
query: Type.String({ description: "Natural language search query" }),
|
|
7574
|
-
limit: Type.Optional(Type.Number({ description: "Max results (default 5)" }))
|
|
7575
|
-
}),
|
|
7576
|
-
async execute(_id, params) {
|
|
7577
|
-
const { agent, diaryId } = ensureConnected(config);
|
|
7578
|
-
const results = await agent.entries.search({
|
|
7579
|
-
diaryId,
|
|
7580
|
-
query: params.query,
|
|
7581
|
-
limit: params.limit ?? 5
|
|
7582
|
-
});
|
|
7583
|
-
return {
|
|
7584
|
-
content: [{
|
|
7585
|
-
type: "text",
|
|
7586
|
-
text: JSON.stringify(results.results?.map((e) => ({
|
|
7587
|
-
id: e.id,
|
|
7588
|
-
title: e.title,
|
|
7589
|
-
tags: e.tags,
|
|
7590
|
-
importance: e.importance,
|
|
7591
|
-
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
7592
|
-
})), null, 2)
|
|
7593
|
-
}],
|
|
7594
|
-
details: {}
|
|
7595
|
-
};
|
|
7596
|
-
}
|
|
7597
|
-
}),
|
|
7598
|
-
defineTool({
|
|
7599
|
-
name: "moltnet_create_entry",
|
|
7600
|
-
label: "Create MoltNet Diary Entry",
|
|
7601
|
-
description: "Create a new diary entry to record decisions, findings, incidents, or reflections.",
|
|
7602
|
-
parameters: Type.Object({
|
|
7603
|
-
title: Type.String({ description: "Entry title (concise, descriptive)" }),
|
|
7604
|
-
content: Type.String({ description: "Entry content (markdown)" }),
|
|
7605
|
-
tags: Type.Optional(Type.Array(Type.String(), { description: "Tags for categorization" })),
|
|
7606
|
-
importance: Type.Optional(Type.Number({ description: "Importance 1-10 (default 5)" }))
|
|
7607
|
-
}),
|
|
7608
|
-
async execute(_id, params) {
|
|
7609
|
-
const { agent, diaryId } = ensureConnected(config);
|
|
7610
|
-
const entry = await agent.entries.create(diaryId, {
|
|
7611
|
-
title: params.title,
|
|
7612
|
-
content: params.content,
|
|
7613
|
-
tags: params.tags ?? [],
|
|
7614
|
-
importance: params.importance ?? 5
|
|
7615
|
-
});
|
|
7616
|
-
return {
|
|
7617
|
-
content: [{
|
|
7618
|
-
type: "text",
|
|
7619
|
-
text: JSON.stringify({
|
|
7620
|
-
id: entry.id,
|
|
7621
|
-
title: entry.title,
|
|
7622
|
-
createdAt: entry.createdAt
|
|
7623
|
-
}, null, 2)
|
|
7624
|
-
}],
|
|
7625
|
-
details: {}
|
|
7626
|
-
};
|
|
7627
|
-
}
|
|
7628
|
-
}),
|
|
7629
|
-
defineTool({
|
|
7630
|
-
name: "moltnet_review_session_errors",
|
|
7631
|
-
label: "Review Session Tool Errors",
|
|
7632
|
-
description: "Review tool failures buffered during this session (isError=true results). Use this to decide whether any failures are worth persisting as a diary entry via moltnet_create_entry. Most failures are transient (denied prompts, empty greps, mid-iteration typecheck errors) and should NOT be written to the diary — only persist incidents that represent a real finding (root cause identified, non-obvious workaround, recurring pattern). Pass clear=true to drop the buffer after reviewing.",
|
|
7633
|
-
parameters: Type.Object({ clear: Type.Optional(Type.Boolean({ description: "If true, empty the buffer after returning it. Use once you have decided whether to persist." })) }),
|
|
7634
|
-
async execute(_id, params) {
|
|
7635
|
-
const errors = config.getSessionErrors();
|
|
7636
|
-
const payload = {
|
|
7637
|
-
count: errors.length,
|
|
7638
|
-
errors: errors.map((e) => ({
|
|
7639
|
-
toolName: e.toolName,
|
|
7640
|
-
toolCallId: e.toolCallId,
|
|
7641
|
-
timestamp: new Date(e.timestamp).toISOString(),
|
|
7642
|
-
input: e.input,
|
|
7643
|
-
error: e.error
|
|
7644
|
-
}))
|
|
7645
|
-
};
|
|
7646
|
-
if (params.clear) config.clearSessionErrors();
|
|
7647
|
-
return {
|
|
7648
|
-
content: [{
|
|
7649
|
-
type: "text",
|
|
7650
|
-
text: JSON.stringify(payload, null, 2)
|
|
7651
|
-
}],
|
|
7652
|
-
details: {}
|
|
7653
|
-
};
|
|
7654
|
-
}
|
|
7655
8152
|
})
|
|
7656
8153
|
];
|
|
7657
8154
|
}
|
|
@@ -7987,10 +8484,6 @@ function createGondolinBashOps(vm, localCwd) {
|
|
|
7987
8484
|
}
|
|
7988
8485
|
//#endregion
|
|
7989
8486
|
//#region src/vm-manager.ts
|
|
7990
|
-
/**
|
|
7991
|
-
* VM lifecycle manager: resume checkpoint, inject credentials, configure
|
|
7992
|
-
* egress, fix TLS, and provide clean shutdown.
|
|
7993
|
-
*/
|
|
7994
8487
|
var GUEST_WORKSPACE$1 = "/workspace";
|
|
7995
8488
|
/**
|
|
7996
8489
|
* Resolve the main worktree root (where .moltnet/ lives — it's untracked,
|
|
@@ -8021,6 +8514,15 @@ function loadCredentials(agentDir) {
|
|
|
8021
8514
|
const sshPrivateKey = existsSync(path.join(sshDir, "id_ed25519")) ? readFileSync(path.join(sshDir, "id_ed25519"), "utf8") : null;
|
|
8022
8515
|
const sshPublicKey = existsSync(path.join(sshDir, "id_ed25519.pub")) ? readFileSync(path.join(sshDir, "id_ed25519.pub"), "utf8") : null;
|
|
8023
8516
|
const allowedSigners = existsSync(path.join(sshDir, "allowed_signers")) ? readFileSync(path.join(sshDir, "allowed_signers"), "utf8") : null;
|
|
8517
|
+
let githubAppPem = null;
|
|
8518
|
+
let githubAppPemFilename = null;
|
|
8519
|
+
const pemPath = JSON.parse(moltnetJson).github?.private_key_path;
|
|
8520
|
+
if (pemPath) if (!existsSync(pemPath)) process.stderr.write(`[pi-extension] Warning: github.private_key_path not found at ${pemPath} — moltnet github token will fail inside the guest
|
|
8521
|
+
`);
|
|
8522
|
+
else {
|
|
8523
|
+
githubAppPem = readFileSync(pemPath, "utf8");
|
|
8524
|
+
githubAppPemFilename = path.basename(pemPath);
|
|
8525
|
+
}
|
|
8024
8526
|
return {
|
|
8025
8527
|
moltnetJson,
|
|
8026
8528
|
agentEnvRaw,
|
|
@@ -8029,7 +8531,9 @@ function loadCredentials(agentDir) {
|
|
|
8029
8531
|
gitconfig,
|
|
8030
8532
|
sshPrivateKey,
|
|
8031
8533
|
sshPublicKey,
|
|
8032
|
-
allowedSigners
|
|
8534
|
+
allowedSigners,
|
|
8535
|
+
githubAppPem,
|
|
8536
|
+
githubAppPemFilename
|
|
8033
8537
|
};
|
|
8034
8538
|
}
|
|
8035
8539
|
/**
|
|
@@ -8076,13 +8580,15 @@ async function resumeVm(config) {
|
|
|
8076
8580
|
apiHost,
|
|
8077
8581
|
...config.extraAllowedHosts ?? []
|
|
8078
8582
|
] });
|
|
8583
|
+
const vmAgentDir = `/home/agent/.moltnet/${config.agentName}`;
|
|
8079
8584
|
const vmAgentEnv = {};
|
|
8080
8585
|
for (const [k, v] of Object.entries(creds.agentEnv)) {
|
|
8081
8586
|
if (v === void 0 || v === "") continue;
|
|
8082
|
-
if (k === "GIT_CONFIG_GLOBAL") vmAgentEnv[k] =
|
|
8083
|
-
else if (k.endsWith("_PRIVATE_KEY_PATH")) vmAgentEnv[k] =
|
|
8587
|
+
if (k === "GIT_CONFIG_GLOBAL") vmAgentEnv[k] = `${vmAgentDir}/gitconfig`;
|
|
8588
|
+
else if (k.endsWith("_PRIVATE_KEY_PATH")) vmAgentEnv[k] = `${vmAgentDir}/${path.basename(v)}`;
|
|
8084
8589
|
else vmAgentEnv[k] = v;
|
|
8085
8590
|
}
|
|
8591
|
+
vmAgentEnv.MOLTNET_CREDENTIALS_PATH = `${vmAgentDir}/moltnet.json`;
|
|
8086
8592
|
const vfsConfig = config.sandboxConfig?.vfs;
|
|
8087
8593
|
let workspaceProvider = new RealFSProvider(config.mountPath);
|
|
8088
8594
|
if (vfsConfig?.shadow?.length) {
|
|
@@ -8117,11 +8623,11 @@ async function resumeVm(config) {
|
|
|
8117
8623
|
'`);
|
|
8118
8624
|
await vm.exec(`sh -c 'echo "nameserver 8.8.8.8
|
|
8119
8625
|
nameserver 1.1.1.1" > /etc/resolv.conf'`);
|
|
8120
|
-
const vmAgentDir = `/home/agent/.moltnet/${config.agentName}`;
|
|
8121
8626
|
const vmSshDir = `${vmAgentDir}/ssh`;
|
|
8122
8627
|
await vm.exec(`mkdir -p ${vmAgentDir}/ssh /home/agent/.pi/agent`);
|
|
8123
8628
|
await vm.fs.writeFile("/home/agent/.pi/agent/auth.json", creds.piAuthJson, { mode: 384 });
|
|
8124
|
-
|
|
8629
|
+
const vmMoltnetJson = rewriteMoltnetJsonPaths(creds.moltnetJson, vmAgentDir, vmSshDir, creds.githubAppPemFilename);
|
|
8630
|
+
await vm.fs.writeFile(`${vmAgentDir}/moltnet.json`, vmMoltnetJson, { mode: 384 });
|
|
8125
8631
|
await vm.fs.writeFile(`${vmAgentDir}/env`, creds.agentEnvRaw, { mode: 384 });
|
|
8126
8632
|
if (creds.gitconfig) {
|
|
8127
8633
|
const vmSigningKey = `${vmSshDir}/id_ed25519`;
|
|
@@ -8132,6 +8638,7 @@ nameserver 1.1.1.1" > /etc/resolv.conf'`);
|
|
|
8132
8638
|
if (creds.sshPrivateKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519`, creds.sshPrivateKey, { mode: 384 });
|
|
8133
8639
|
if (creds.sshPublicKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519.pub`, creds.sshPublicKey, { mode: 420 });
|
|
8134
8640
|
if (creds.allowedSigners) await vm.fs.writeFile(`${vmSshDir}/allowed_signers`, creds.allowedSigners, { mode: 420 });
|
|
8641
|
+
if (creds.githubAppPem && creds.githubAppPemFilename) await vm.fs.writeFile(`${vmAgentDir}/${creds.githubAppPemFilename}`, creds.githubAppPem, { mode: 384 });
|
|
8135
8642
|
await vm.exec("chown -R agent:agent /home/agent/.pi /home/agent/.moltnet");
|
|
8136
8643
|
return {
|
|
8137
8644
|
vm,
|
|
@@ -8142,6 +8649,43 @@ nameserver 1.1.1.1" > /etc/resolv.conf'`);
|
|
|
8142
8649
|
};
|
|
8143
8650
|
}
|
|
8144
8651
|
/**
|
|
8652
|
+
* Rewrite host-absolute paths inside moltnet.json to VM-local equivalents.
|
|
8653
|
+
*
|
|
8654
|
+
* Fields rewritten:
|
|
8655
|
+
* ssh.private_key_path → <vmSshDir>/<basename of original>
|
|
8656
|
+
* ssh.public_key_path → <vmSshDir>/<basename of original>
|
|
8657
|
+
* git.config_path → <vmAgentDir>/gitconfig
|
|
8658
|
+
* github.private_key_path → <vmAgentDir>/<pemFilename> (if present)
|
|
8659
|
+
*
|
|
8660
|
+
* All other fields are passed through unchanged.
|
|
8661
|
+
* Throws if moltnetJson is not valid JSON — callers must not inject a broken
|
|
8662
|
+
* moltnet.json into the guest.
|
|
8663
|
+
*/
|
|
8664
|
+
function rewriteMoltnetJsonPaths(moltnetJson, vmAgentDir, vmSshDir, githubAppPemFilename) {
|
|
8665
|
+
const config = JSON.parse(moltnetJson);
|
|
8666
|
+
if (config.ssh && typeof config.ssh === "object") {
|
|
8667
|
+
const ssh = config.ssh;
|
|
8668
|
+
const origPrivate = typeof ssh.private_key_path === "string" ? ssh.private_key_path : null;
|
|
8669
|
+
const origPublic = typeof ssh.public_key_path === "string" ? ssh.public_key_path : null;
|
|
8670
|
+
config.ssh = {
|
|
8671
|
+
...ssh,
|
|
8672
|
+
...origPrivate !== null && { private_key_path: `${vmSshDir}/${path.basename(origPrivate)}` },
|
|
8673
|
+
...origPublic !== null && { public_key_path: `${vmSshDir}/${path.basename(origPublic)}` }
|
|
8674
|
+
};
|
|
8675
|
+
}
|
|
8676
|
+
if (config.git && typeof config.git === "object") {
|
|
8677
|
+
const git = { ...config.git };
|
|
8678
|
+
git.config_path = `${vmAgentDir}/gitconfig`;
|
|
8679
|
+
config.git = git;
|
|
8680
|
+
}
|
|
8681
|
+
if (githubAppPemFilename && config.github && typeof config.github === "object") {
|
|
8682
|
+
const github = { ...config.github };
|
|
8683
|
+
github.private_key_path = `${vmAgentDir}/${githubAppPemFilename}`;
|
|
8684
|
+
config.github = github;
|
|
8685
|
+
}
|
|
8686
|
+
return JSON.stringify(config);
|
|
8687
|
+
}
|
|
8688
|
+
/**
|
|
8145
8689
|
* Ensure `[worktree] useRelativePaths = true` is set in the given
|
|
8146
8690
|
* gitconfig text. If the section exists, rewrite the key; otherwise
|
|
8147
8691
|
* append a new section.
|
|
@@ -8179,9 +8723,9 @@ if (!FormatRegistry.Has("date-time")) FormatRegistry.Set("date-time", (v) => !Nu
|
|
|
8179
8723
|
* own signed rows and CIDv1 lookup. The schema below is designed to
|
|
8180
8724
|
* carry forward unchanged — only storage and addressing differ.
|
|
8181
8725
|
*
|
|
8182
|
-
* Until Phase 2 lands, `
|
|
8726
|
+
* Until Phase 2 lands, `rubricId` + `version` + `contentHash` are
|
|
8183
8727
|
* informational fields the author fills in; no uniqueness is enforced.
|
|
8184
|
-
* `
|
|
8728
|
+
* `contentHash` is optional in Phase 1 because the *task*'s input_cid
|
|
8185
8729
|
* is the authoritative commitment.
|
|
8186
8730
|
*/
|
|
8187
8731
|
/**
|
|
@@ -8217,12 +8761,12 @@ var RubricCriterion = Type$1.Object({
|
|
|
8217
8761
|
* (stored row `body`); only the addressing mechanism differs.
|
|
8218
8762
|
*/
|
|
8219
8763
|
var Rubric = Type$1.Object({
|
|
8220
|
-
|
|
8764
|
+
rubricId: Type$1.String({ minLength: 1 }),
|
|
8221
8765
|
version: Type$1.String({ minLength: 1 }),
|
|
8222
8766
|
preamble: Type$1.Optional(Type$1.String()),
|
|
8223
8767
|
criteria: Type$1.Array(RubricCriterion, { minItems: 1 }),
|
|
8224
8768
|
scope: Type$1.Optional(Type$1.String()),
|
|
8225
|
-
|
|
8769
|
+
contentHash: Type$1.Optional(Type$1.String())
|
|
8226
8770
|
}, {
|
|
8227
8771
|
$id: "Rubric",
|
|
8228
8772
|
additionalProperties: false
|
|
@@ -8278,25 +8822,25 @@ var AssessBriefCriterion = Type$1.Object({
|
|
|
8278
8822
|
additionalProperties: false
|
|
8279
8823
|
});
|
|
8280
8824
|
var AssessBriefInput = Type$1.Object({
|
|
8281
|
-
|
|
8825
|
+
targetTaskId: Type$1.String({ format: "uuid" }),
|
|
8282
8826
|
criteria: Type$1.Array(AssessBriefCriterion, { minItems: 1 }),
|
|
8283
|
-
|
|
8827
|
+
rubricPreamble: Type$1.Optional(Type$1.String())
|
|
8284
8828
|
}, {
|
|
8285
8829
|
$id: "AssessBriefInput",
|
|
8286
8830
|
additionalProperties: false
|
|
8287
8831
|
});
|
|
8288
8832
|
/** One score line. */
|
|
8289
8833
|
var AssessBriefScore = Type$1.Object({
|
|
8290
|
-
|
|
8834
|
+
criterionId: Type$1.String({ minLength: 1 }),
|
|
8291
8835
|
score: Type$1.Number({
|
|
8292
8836
|
minimum: 0,
|
|
8293
8837
|
maximum: 1
|
|
8294
8838
|
}),
|
|
8295
8839
|
rationale: Type$1.Optional(Type$1.String()),
|
|
8296
8840
|
evidence: Type$1.Optional(Type$1.Object({
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8841
|
+
commitsVerified: Type$1.Number(),
|
|
8842
|
+
commitsTotal: Type$1.Number(),
|
|
8843
|
+
signatureFailures: Type$1.Array(Type$1.String())
|
|
8300
8844
|
}, { additionalProperties: false }))
|
|
8301
8845
|
}, {
|
|
8302
8846
|
$id: "AssessBriefScore",
|
|
@@ -8309,7 +8853,7 @@ var AssessBriefOutput = Type$1.Object({
|
|
|
8309
8853
|
maximum: 1
|
|
8310
8854
|
}),
|
|
8311
8855
|
verdict: Type$1.String({ minLength: 1 }),
|
|
8312
|
-
|
|
8856
|
+
judgeModel: Type$1.Optional(Type$1.String())
|
|
8313
8857
|
}, {
|
|
8314
8858
|
$id: "AssessBriefOutput",
|
|
8315
8859
|
additionalProperties: false
|
|
@@ -8340,15 +8884,15 @@ var EntryTypeFilter = Type$1.Union([
|
|
|
8340
8884
|
Type$1.Literal("reflection")
|
|
8341
8885
|
]);
|
|
8342
8886
|
var CuratePackInput = Type$1.Object({
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8887
|
+
diaryId: Type$1.String({ format: "uuid" }),
|
|
8888
|
+
taskPrompt: Type$1.String({ minLength: 1 }),
|
|
8889
|
+
entryTypes: Type$1.Optional(Type$1.Array(EntryTypeFilter, { minItems: 1 })),
|
|
8890
|
+
tagFilters: Type$1.Optional(Type$1.Object({
|
|
8347
8891
|
include: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8348
8892
|
exclude: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8349
8893
|
prefix: Type$1.Optional(Type$1.String())
|
|
8350
8894
|
}, { additionalProperties: false })),
|
|
8351
|
-
|
|
8895
|
+
tokenBudget: Type$1.Optional(Type$1.Number({ minimum: 500 })),
|
|
8352
8896
|
recipe: Type$1.Optional(Type$1.Union([Type$1.Literal("topic-focused-v1"), Type$1.Literal("scope-inventory-v1")]))
|
|
8353
8897
|
}, {
|
|
8354
8898
|
$id: "CuratePackInput",
|
|
@@ -8360,18 +8904,18 @@ var CuratePackInput = Type$1.Object({
|
|
|
8360
8904
|
* is the receipt.
|
|
8361
8905
|
*/
|
|
8362
8906
|
var CuratePackOutput = Type$1.Object({
|
|
8363
|
-
|
|
8364
|
-
|
|
8907
|
+
packId: Type$1.String({ format: "uuid" }),
|
|
8908
|
+
packCid: Type$1.String({ minLength: 1 }),
|
|
8365
8909
|
entries: Type$1.Array(Type$1.Object({
|
|
8366
|
-
|
|
8910
|
+
entryId: Type$1.String({ format: "uuid" }),
|
|
8367
8911
|
rank: Type$1.Number({ minimum: 1 }),
|
|
8368
8912
|
rationale: Type$1.String({ minLength: 1 })
|
|
8369
8913
|
}, { additionalProperties: false }), { minItems: 1 }),
|
|
8370
|
-
|
|
8914
|
+
recipeParams: Type$1.Record(Type$1.String(), Type$1.Unknown()),
|
|
8371
8915
|
checkpoints: Type$1.Optional(Type$1.Array(Type$1.Object({
|
|
8372
8916
|
phase: Type$1.String({ minLength: 1 }),
|
|
8373
|
-
|
|
8374
|
-
|
|
8917
|
+
candidateIds: Type$1.Array(Type$1.String({ format: "uuid" })),
|
|
8918
|
+
droppedIds: Type$1.Optional(Type$1.Array(Type$1.String({ format: "uuid" }))),
|
|
8375
8919
|
notes: Type$1.String({ minLength: 1 })
|
|
8376
8920
|
}, { additionalProperties: false }))),
|
|
8377
8921
|
summary: Type$1.String({ minLength: 1 })
|
|
@@ -8392,9 +8936,9 @@ var FULFILL_BRIEF_TYPE = "fulfill_brief";
|
|
|
8392
8936
|
var FulfillBriefInput = Type$1.Object({
|
|
8393
8937
|
brief: Type$1.String({ minLength: 1 }),
|
|
8394
8938
|
title: Type$1.Optional(Type$1.String()),
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8939
|
+
acceptanceCriteria: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8940
|
+
seedFiles: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8941
|
+
scopeHint: Type$1.Optional(Type$1.String())
|
|
8398
8942
|
}, {
|
|
8399
8943
|
$id: "FulfillBriefInput",
|
|
8400
8944
|
additionalProperties: false
|
|
@@ -8408,10 +8952,10 @@ var FulfillBriefOutput = Type$1.Object({
|
|
|
8408
8952
|
commits: Type$1.Array(Type$1.Object({
|
|
8409
8953
|
sha: Type$1.String({ minLength: 7 }),
|
|
8410
8954
|
message: Type$1.String(),
|
|
8411
|
-
|
|
8955
|
+
diaryEntryId: Type$1.Union([Type$1.String({ format: "uuid" }), Type$1.Null()])
|
|
8412
8956
|
}, { additionalProperties: false })),
|
|
8413
|
-
|
|
8414
|
-
|
|
8957
|
+
pullRequestUrl: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
8958
|
+
diaryEntryIds: Type$1.Array(Type$1.String({ format: "uuid" })),
|
|
8415
8959
|
summary: Type$1.String({ minLength: 1 })
|
|
8416
8960
|
}, {
|
|
8417
8961
|
$id: "FulfillBriefOutput",
|
|
@@ -8442,8 +8986,8 @@ var FulfillBriefOutput = Type$1.Object({
|
|
|
8442
8986
|
*/
|
|
8443
8987
|
var JUDGE_PACK_TYPE = "judge_pack";
|
|
8444
8988
|
var JudgePackInput = Type$1.Object({
|
|
8445
|
-
|
|
8446
|
-
|
|
8989
|
+
renderedPackId: Type$1.String({ format: "uuid" }),
|
|
8990
|
+
sourcePackId: Type$1.String({ format: "uuid" }),
|
|
8447
8991
|
rubric: Rubric
|
|
8448
8992
|
}, {
|
|
8449
8993
|
$id: "JudgePackInput",
|
|
@@ -8451,7 +8995,7 @@ var JudgePackInput = Type$1.Object({
|
|
|
8451
8995
|
});
|
|
8452
8996
|
/** One scored criterion. Mirrors `AssessBriefScore`. */
|
|
8453
8997
|
var JudgePackScore = Type$1.Object({
|
|
8454
|
-
|
|
8998
|
+
criterionId: Type$1.String({ minLength: 1 }),
|
|
8455
8999
|
score: Type$1.Number({
|
|
8456
9000
|
minimum: 0,
|
|
8457
9001
|
maximum: 1
|
|
@@ -8469,8 +9013,8 @@ var JudgePackOutput = Type$1.Object({
|
|
|
8469
9013
|
maximum: 1
|
|
8470
9014
|
}),
|
|
8471
9015
|
verdict: Type$1.String({ minLength: 1 }),
|
|
8472
|
-
|
|
8473
|
-
|
|
9016
|
+
judgeModel: Type$1.Optional(Type$1.String()),
|
|
9017
|
+
rendererBinaryCid: Type$1.Optional(Type$1.Union([Type$1.String(), Type$1.Null()]))
|
|
8474
9018
|
}, {
|
|
8475
9019
|
$id: "JudgePackOutput",
|
|
8476
9020
|
additionalProperties: false
|
|
@@ -8494,7 +9038,7 @@ var JudgePackOutput = Type$1.Object({
|
|
|
8494
9038
|
*/
|
|
8495
9039
|
var RENDER_PACK_TYPE = "render_pack";
|
|
8496
9040
|
var RenderPackInput = Type$1.Object({
|
|
8497
|
-
|
|
9041
|
+
packId: Type$1.String({ format: "uuid" }),
|
|
8498
9042
|
persist: Type$1.Optional(Type$1.Boolean()),
|
|
8499
9043
|
pinned: Type$1.Optional(Type$1.Boolean())
|
|
8500
9044
|
}, {
|
|
@@ -8502,11 +9046,11 @@ var RenderPackInput = Type$1.Object({
|
|
|
8502
9046
|
additionalProperties: false
|
|
8503
9047
|
});
|
|
8504
9048
|
var RenderPackOutput = Type$1.Object({
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
9049
|
+
renderedPackId: Type$1.Union([Type$1.String({ format: "uuid" }), Type$1.Null()]),
|
|
9050
|
+
renderedCid: Type$1.String({ minLength: 1 }),
|
|
9051
|
+
renderMethod: Type$1.String({ minLength: 1 }),
|
|
9052
|
+
byteSize: Type$1.Number({ minimum: 0 }),
|
|
9053
|
+
entriesRendered: Type$1.Number({ minimum: 0 }),
|
|
8510
9054
|
summary: Type$1.String({ minLength: 1 })
|
|
8511
9055
|
}, {
|
|
8512
9056
|
$id: "RenderPackOutput",
|
|
@@ -8578,6 +9122,30 @@ new Proxy({}, { get(_, prop) {
|
|
|
8578
9122
|
return getTaskTypeRegistry().get(prop);
|
|
8579
9123
|
} });
|
|
8580
9124
|
//#endregion
|
|
9125
|
+
//#region ../tasks/src/validation.ts
|
|
9126
|
+
function getTaskTypeEntry(taskType) {
|
|
9127
|
+
const taskTypes = BUILT_IN_TASK_TYPES;
|
|
9128
|
+
if (!Object.prototype.hasOwnProperty.call(taskTypes, taskType)) return;
|
|
9129
|
+
return taskTypes[taskType];
|
|
9130
|
+
}
|
|
9131
|
+
function formatField(prefix, path) {
|
|
9132
|
+
return path ? `${prefix}${path}` : prefix;
|
|
9133
|
+
}
|
|
9134
|
+
function schemaErrors(prefix, schema, value) {
|
|
9135
|
+
return [...Value.Errors(schema, value)].map((error) => ({
|
|
9136
|
+
field: formatField(prefix, error.path),
|
|
9137
|
+
message: error.message
|
|
9138
|
+
}));
|
|
9139
|
+
}
|
|
9140
|
+
function validateTaskOutput(taskType, output) {
|
|
9141
|
+
const entry = getTaskTypeEntry(taskType);
|
|
9142
|
+
if (!entry) return [{
|
|
9143
|
+
field: "taskType",
|
|
9144
|
+
message: `Unknown task type: ${taskType}`
|
|
9145
|
+
}];
|
|
9146
|
+
return schemaErrors("output", entry.outputSchema, output);
|
|
9147
|
+
}
|
|
9148
|
+
//#endregion
|
|
8581
9149
|
//#region ../tasks/src/wire.ts
|
|
8582
9150
|
/**
|
|
8583
9151
|
* Wire-format types for the MoltNet Task model.
|
|
@@ -8589,7 +9157,7 @@ new Proxy({}, { get(_, prop) {
|
|
|
8589
9157
|
* - `TaskReporter` output records (PR 0)
|
|
8590
9158
|
*
|
|
8591
9159
|
* Invariant: every property on `Task` is type-neutral (applies to all
|
|
8592
|
-
* `
|
|
9160
|
+
* `taskType`s). Type-specific payloads live inside `input` / `output`
|
|
8593
9161
|
* JSONB, validated against schemas registered under `task_types`.
|
|
8594
9162
|
*
|
|
8595
9163
|
* Identity rule:
|
|
@@ -8632,8 +9200,8 @@ var IsoTimestamp = Type$1.String({ format: "date-time" });
|
|
|
8632
9200
|
* Embedded in `tasks.references` JSONB array.
|
|
8633
9201
|
*/
|
|
8634
9202
|
var TaskRef = Type$1.Object({
|
|
8635
|
-
|
|
8636
|
-
|
|
9203
|
+
taskId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9204
|
+
outputCid: Cid,
|
|
8637
9205
|
role: Type$1.Union([
|
|
8638
9206
|
Type$1.Literal("judged_work"),
|
|
8639
9207
|
Type$1.Literal("reviewed_diff"),
|
|
@@ -8662,11 +9230,11 @@ var TaskRef = Type$1.Object({
|
|
|
8662
9230
|
* `TaskOutput.usage` for convenience.
|
|
8663
9231
|
*/
|
|
8664
9232
|
var TaskUsage = Type$1.Object({
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
9233
|
+
inputTokens: Type$1.Integer({ minimum: 0 }),
|
|
9234
|
+
outputTokens: Type$1.Integer({ minimum: 0 }),
|
|
9235
|
+
cacheReadTokens: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
9236
|
+
cacheWriteTokens: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
9237
|
+
toolCalls: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
8670
9238
|
model: Type$1.Optional(Type$1.String()),
|
|
8671
9239
|
provider: Type$1.Optional(Type$1.String())
|
|
8672
9240
|
}, {
|
|
@@ -8686,62 +9254,65 @@ var TaskError = Type$1.Object({
|
|
|
8686
9254
|
additionalProperties: false
|
|
8687
9255
|
});
|
|
8688
9256
|
Type$1.Object({
|
|
8689
|
-
|
|
8690
|
-
|
|
9257
|
+
agentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9258
|
+
humanId: Type$1.Union([Uuid, Type$1.Null()])
|
|
8691
9259
|
}, {
|
|
8692
9260
|
$id: "ActorPair",
|
|
8693
9261
|
additionalProperties: false
|
|
8694
9262
|
});
|
|
8695
9263
|
Type$1.Object({
|
|
8696
9264
|
id: Uuid,
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
9265
|
+
taskType: Type$1.String({ minLength: 1 }),
|
|
9266
|
+
teamId: Uuid,
|
|
9267
|
+
diaryId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9268
|
+
outputKind: OutputKind,
|
|
8701
9269
|
input: Type$1.Record(Type$1.String(), Type$1.Unknown()),
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
9270
|
+
inputSchemaCid: Cid,
|
|
9271
|
+
inputCid: Cid,
|
|
9272
|
+
criteriaCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8705
9273
|
references: Type$1.Array(TaskRef),
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
9274
|
+
correlationId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9275
|
+
imposedByAgentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9276
|
+
imposedByHumanId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9277
|
+
acceptedAttemptN: Type$1.Union([Type$1.Number(), Type$1.Null()]),
|
|
8710
9278
|
status: TaskStatus,
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
9279
|
+
queuedAt: IsoTimestamp,
|
|
9280
|
+
completedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9281
|
+
expiresAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9282
|
+
cancelledByAgentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9283
|
+
cancelledByHumanId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9284
|
+
cancelReason: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
9285
|
+
maxAttempts: Type$1.Number({ minimum: 1 })
|
|
8718
9286
|
}, {
|
|
8719
9287
|
$id: "Task",
|
|
8720
9288
|
additionalProperties: false
|
|
8721
9289
|
});
|
|
8722
9290
|
Type$1.Object({
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
9291
|
+
taskId: Uuid,
|
|
9292
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
9293
|
+
claimedByAgentId: Uuid,
|
|
9294
|
+
runtimeId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9295
|
+
claimedAt: IsoTimestamp,
|
|
9296
|
+
startedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9297
|
+
completedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
8730
9298
|
status: TaskAttemptStatus,
|
|
8731
9299
|
output: Type$1.Union([Type$1.Record(Type$1.String(), Type$1.Unknown()), Type$1.Null()]),
|
|
8732
|
-
|
|
9300
|
+
outputCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8733
9301
|
error: Type$1.Union([TaskError, Type$1.Null()]),
|
|
8734
9302
|
usage: Type$1.Union([TaskUsage, Type$1.Null()]),
|
|
8735
|
-
|
|
8736
|
-
|
|
9303
|
+
contentSignature: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
9304
|
+
signedAt: Type$1.Union([IsoTimestamp, Type$1.Null()])
|
|
8737
9305
|
}, {
|
|
8738
9306
|
$id: "TaskAttempt",
|
|
8739
9307
|
additionalProperties: false
|
|
8740
9308
|
});
|
|
8741
9309
|
Type$1.Object({
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
seq: Type$1.Number({
|
|
9310
|
+
taskId: Uuid,
|
|
9311
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
9312
|
+
seq: Type$1.Number({
|
|
9313
|
+
minimum: 0,
|
|
9314
|
+
description: "Monotonically increasing integer assigned by the server. Use as the afterSeq cursor on the list-messages endpoint to poll for new messages without re-fetching earlier ones."
|
|
9315
|
+
}),
|
|
8745
9316
|
timestamp: IsoTimestamp,
|
|
8746
9317
|
kind: TaskMessageKind,
|
|
8747
9318
|
payload: Type$1.Record(Type$1.String(), Type$1.Unknown())
|
|
@@ -8750,34 +9321,34 @@ Type$1.Object({
|
|
|
8750
9321
|
additionalProperties: false
|
|
8751
9322
|
});
|
|
8752
9323
|
Type$1.Object({
|
|
8753
|
-
|
|
8754
|
-
|
|
9324
|
+
taskId: Uuid,
|
|
9325
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
8755
9326
|
status: Type$1.Union([
|
|
8756
9327
|
Type$1.Literal("completed"),
|
|
8757
9328
|
Type$1.Literal("failed"),
|
|
8758
9329
|
Type$1.Literal("cancelled")
|
|
8759
9330
|
]),
|
|
8760
9331
|
output: Type$1.Union([Type$1.Record(Type$1.String(), Type$1.Unknown()), Type$1.Null()]),
|
|
8761
|
-
|
|
9332
|
+
outputCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8762
9333
|
usage: TaskUsage,
|
|
8763
|
-
|
|
9334
|
+
durationMs: Type$1.Number({ minimum: 0 }),
|
|
8764
9335
|
error: Type$1.Optional(TaskError),
|
|
8765
|
-
|
|
9336
|
+
contentSignature: Type$1.Optional(Type$1.String())
|
|
8766
9337
|
}, {
|
|
8767
9338
|
$id: "TaskOutput",
|
|
8768
9339
|
additionalProperties: false
|
|
8769
9340
|
});
|
|
8770
9341
|
Type$1.Object({
|
|
8771
|
-
|
|
8772
|
-
|
|
9342
|
+
runtimeId: Uuid,
|
|
9343
|
+
agentId: Uuid,
|
|
8773
9344
|
timestamp: IsoTimestamp,
|
|
8774
9345
|
status: Type$1.Union([
|
|
8775
9346
|
Type$1.Literal("idle"),
|
|
8776
9347
|
Type$1.Literal("busy"),
|
|
8777
9348
|
Type$1.Literal("draining")
|
|
8778
9349
|
]),
|
|
8779
|
-
|
|
8780
|
-
|
|
9350
|
+
activeTaskIds: Type$1.Array(Uuid),
|
|
9351
|
+
supportedTaskTypes: Type$1.Array(Type$1.String())
|
|
8781
9352
|
}, {
|
|
8782
9353
|
$id: "RuntimeHeartbeat",
|
|
8783
9354
|
additionalProperties: false
|
|
@@ -8798,10 +9369,10 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8798
9369
|
...ctx.target.diaryEntryIds.map((id) => `- ${id}`),
|
|
8799
9370
|
""
|
|
8800
9371
|
].join("\n") : "";
|
|
8801
|
-
const preambleSection = input.
|
|
9372
|
+
const preambleSection = input.rubricPreamble ? [
|
|
8802
9373
|
"### Rubric preamble",
|
|
8803
9374
|
"",
|
|
8804
|
-
input.
|
|
9375
|
+
input.rubricPreamble,
|
|
8805
9376
|
""
|
|
8806
9377
|
].join("\n") : "";
|
|
8807
9378
|
return [
|
|
@@ -8832,12 +9403,12 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8832
9403
|
"",
|
|
8833
9404
|
"- `llm_judged`: score 0..1 continuous. `rationale` REQUIRED (2–4 sentences).",
|
|
8834
9405
|
"- `boolean`: score exactly 0 or 1. `rationale` optional.",
|
|
8835
|
-
"- `deterministic_signature_check`: run `moltnet entry verify` on every diary entry listed above AND `git verify-commit` on every commit. Score 1 iff ALL signatures are valid; otherwise 0. Populate `evidence.
|
|
9406
|
+
"- `deterministic_signature_check`: run `moltnet entry verify` on every diary entry listed above AND `git verify-commit` on every commit. Score 1 iff ALL signatures are valid; otherwise 0. Populate `evidence.commitsVerified`, `evidence.commitsTotal`, `evidence.signatureFailures`.",
|
|
8836
9407
|
"",
|
|
8837
9408
|
"### Final output",
|
|
8838
9409
|
"",
|
|
8839
9410
|
"Emit a JSON object matching `AssessBriefOutput`:",
|
|
8840
|
-
" { \"scores\": [{
|
|
9411
|
+
" { \"scores\": [{criterionId, score, rationale?, evidence?}], \"composite\", \"verdict\", \"judgeModel\"? }",
|
|
8841
9412
|
"`composite` = Σ(weight_i × score_i) recomputed. The runtime will reject a mismatch.",
|
|
8842
9413
|
"Write a signed diary entry (tags: \"judgment\", \"assess_brief\") capturing the rationale before emitting the JSON."
|
|
8843
9414
|
].filter(Boolean).join("\n");
|
|
@@ -8859,7 +9430,7 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8859
9430
|
* N isolated `createAgentSession` children (one per tag cluster or
|
|
8860
9431
|
* entry_type axis the curator picks after recon), each with a narrow
|
|
8861
9432
|
* tool subset and a turn cap, and returns compressed summaries. Parent
|
|
8862
|
-
* curator keeps a warm context and only sees {
|
|
9433
|
+
* curator keeps a warm context and only sees {candidateIds, notes}
|
|
8863
9434
|
* per probe — mirrors the fan-out pattern pi-mono SDK example #13
|
|
8864
9435
|
* (session runtime) + #05 (custom tools) makes possible. Until that
|
|
8865
9436
|
* lands, the `checkpoints[]` output field is the fallback: curator
|
|
@@ -8867,7 +9438,7 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8867
9438
|
* resume without replaying the tool history.
|
|
8868
9439
|
*/
|
|
8869
9440
|
function buildCuratePackPrompt(input, ctx) {
|
|
8870
|
-
const {
|
|
9441
|
+
const { diaryId, taskPrompt, entryTypes, tagFilters, tokenBudget, recipe } = input;
|
|
8871
9442
|
const effectiveEntryTypes = entryTypes ?? [
|
|
8872
9443
|
"semantic",
|
|
8873
9444
|
"episodic",
|
|
@@ -8954,7 +9525,7 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8954
9525
|
"",
|
|
8955
9526
|
"The tool returns a JSON payload whose top-level fields are `packId` and",
|
|
8956
9527
|
"`packCid` (NOT `id`). Copy those exact UUID/CID strings verbatim into",
|
|
8957
|
-
"`
|
|
9528
|
+
"`packId` and `packCid` in your final output — do not substitute an",
|
|
8958
9529
|
"entry id, do not reformat, do not fabricate a UUID.",
|
|
8959
9530
|
"",
|
|
8960
9531
|
"## Hard constraints",
|
|
@@ -8971,14 +9542,14 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8971
9542
|
"Write to stdout a JSON object matching `CuratePackOutput`:",
|
|
8972
9543
|
"```",
|
|
8973
9544
|
"{",
|
|
8974
|
-
" \"
|
|
8975
|
-
" \"
|
|
9545
|
+
" \"packId\": \"<uuid>\",",
|
|
9546
|
+
" \"packCid\": \"<cid>\",",
|
|
8976
9547
|
" \"entries\": [",
|
|
8977
|
-
" { \"
|
|
9548
|
+
" { \"entryId\": \"<uuid>\", \"rank\": 1, \"rationale\": \"<why>\" }",
|
|
8978
9549
|
" ],",
|
|
8979
|
-
" \"
|
|
9550
|
+
" \"recipeParams\": { \"recipe\": \"...\", \"prompt\": \"...\", ... },",
|
|
8980
9551
|
" \"checkpoints\": [",
|
|
8981
|
-
" { \"phase\": \"recon\", \"
|
|
9552
|
+
" { \"phase\": \"recon\", \"candidateIds\": [...], \"droppedIds\": [...], \"notes\": \"...\" }",
|
|
8982
9553
|
" ],",
|
|
8983
9554
|
" \"summary\": \"<2-4 sentences: what you looked for, how you narrowed, what defines the final set>\"",
|
|
8984
9555
|
"}",
|
|
@@ -8996,7 +9567,7 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8996
9567
|
* is told to inspect them itself.
|
|
8997
9568
|
*/
|
|
8998
9569
|
function buildFulfillBriefPrompt(input, ctx) {
|
|
8999
|
-
const { brief, title,
|
|
9570
|
+
const { brief, title, acceptanceCriteria, seedFiles, scopeHint } = input;
|
|
9000
9571
|
const criteriaSection = acceptanceCriteria?.length ? [
|
|
9001
9572
|
"### Acceptance criteria",
|
|
9002
9573
|
"",
|
|
@@ -9045,14 +9616,14 @@ function buildFulfillBriefPrompt(input, ctx) {
|
|
|
9045
9616
|
"### Final output",
|
|
9046
9617
|
"",
|
|
9047
9618
|
"When done, write to stdout a JSON object with shape matching `FulfillBriefOutput`:",
|
|
9048
|
-
" { \"branch\", \"commits\": [{sha, message,
|
|
9619
|
+
" { \"branch\", \"commits\": [{sha, message, diaryEntryId}], \"pullRequestUrl\", \"diaryEntryIds\", \"summary\" }",
|
|
9049
9620
|
"The runtime parses this as the structured task output. Failing to emit it is a failure."
|
|
9050
9621
|
].filter(Boolean).join("\n");
|
|
9051
9622
|
}
|
|
9052
9623
|
//#endregion
|
|
9053
9624
|
//#region ../agent-runtime/src/prompts/judge-pack.ts
|
|
9054
9625
|
function buildJudgePackPrompt(input, ctx) {
|
|
9055
|
-
const {
|
|
9626
|
+
const { renderedPackId, sourcePackId, rubric } = input;
|
|
9056
9627
|
const criteriaList = rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
|
|
9057
9628
|
const preambleSection = rubric.preamble ? [
|
|
9058
9629
|
"### Rubric preamble",
|
|
@@ -9075,7 +9646,7 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9075
9646
|
"",
|
|
9076
9647
|
`- **Rendered pack**: \`${renderedPackId}\``,
|
|
9077
9648
|
`- **Source pack**: \`${sourcePackId}\``,
|
|
9078
|
-
`- **Rubric**: \`${rubric.
|
|
9649
|
+
`- **Rubric**: \`${rubric.rubricId}\` v${rubric.version}`,
|
|
9079
9650
|
"",
|
|
9080
9651
|
preambleSection,
|
|
9081
9652
|
"## Workflow",
|
|
@@ -9114,12 +9685,12 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9114
9685
|
" non-empty `contentSignature`. If `required_signed_total` is 0,",
|
|
9115
9686
|
" score = 1. Populate `evidence` with `{ entries_verified,",
|
|
9116
9687
|
" entries_total, required_signed_total, required_signed_ok,",
|
|
9117
|
-
"
|
|
9688
|
+
" signatureFailures: [entryIds] }` where `signatureFailures` lists",
|
|
9118
9689
|
" ONLY the REQUIRED-SIGNED entries that lack a signature.",
|
|
9119
9690
|
"- `deterministic_coverage_check`: for every source entry, check",
|
|
9120
|
-
" whether its `
|
|
9691
|
+
" whether its `entryId` (or a stable reference like title + CID",
|
|
9121
9692
|
" prefix) appears in the rendered `content`. Score 1 iff coverage is",
|
|
9122
|
-
" complete; otherwise 0. Populate `evidence` with `{ covered, total, missing: [
|
|
9693
|
+
" complete; otherwise 0. Populate `evidence` with `{ covered, total, missing: [entryIds] }`.",
|
|
9123
9694
|
"",
|
|
9124
9695
|
"## Constraints",
|
|
9125
9696
|
"",
|
|
@@ -9133,17 +9704,17 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9133
9704
|
"Write to stdout a JSON object matching `JudgePackOutput`:",
|
|
9134
9705
|
"```",
|
|
9135
9706
|
"{",
|
|
9136
|
-
" \"scores\": [{\"
|
|
9707
|
+
" \"scores\": [{\"criterionId\": \"...\", \"score\": 0.0, \"rationale\": \"...\", \"evidence\": {...}}],",
|
|
9137
9708
|
" \"composite\": <sum-of-weighted-scores>,",
|
|
9138
9709
|
" \"verdict\": \"<1-3 sentence overall>\",",
|
|
9139
|
-
" \"
|
|
9140
|
-
" \"
|
|
9710
|
+
" \"judgeModel\": \"<provider:model>\",",
|
|
9711
|
+
" \"rendererBinaryCid\": \"<cid-string-only-if-available>\"",
|
|
9141
9712
|
"}",
|
|
9142
9713
|
"```",
|
|
9143
|
-
"Omit `
|
|
9714
|
+
"Omit `rendererBinaryCid` entirely when no binary CID is exposed by",
|
|
9144
9715
|
"`moltnet_rendered_pack_get`. Do NOT emit `null` — the field is optional",
|
|
9145
9716
|
"and absence is the correct representation when unavailable.",
|
|
9146
|
-
`Write a signed diary entry (tags: \`judgment\`, \`judge_pack\`, \`rubric:${rubric.
|
|
9717
|
+
`Write a signed diary entry (tags: \`judgment\`, \`judge_pack\`, \`rubric:${rubric.rubricId}\`) capturing the rationale before`,
|
|
9147
9718
|
"emitting the JSON."
|
|
9148
9719
|
].filter((l) => l !== null).join("\n");
|
|
9149
9720
|
}
|
|
@@ -9154,7 +9725,7 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9154
9725
|
* wraps `moltnet_pack_render` and emits the receipt.
|
|
9155
9726
|
*/
|
|
9156
9727
|
function buildRenderPackPrompt(input, ctx) {
|
|
9157
|
-
const {
|
|
9728
|
+
const { packId, persist = true, pinned = false } = input;
|
|
9158
9729
|
return [
|
|
9159
9730
|
"# Render Pack Agent",
|
|
9160
9731
|
"",
|
|
@@ -9194,11 +9765,11 @@ function buildRenderPackPrompt(input, ctx) {
|
|
|
9194
9765
|
"Write to stdout a JSON object matching `RenderPackOutput`:",
|
|
9195
9766
|
"```",
|
|
9196
9767
|
"{",
|
|
9197
|
-
" \"
|
|
9198
|
-
" \"
|
|
9199
|
-
" \"
|
|
9200
|
-
" \"
|
|
9201
|
-
" \"
|
|
9768
|
+
" \"renderedPackId\": \"<uuid-or-null>\",",
|
|
9769
|
+
" \"renderedCid\": \"<cid>\",",
|
|
9770
|
+
" \"renderMethod\": \"<label>\",",
|
|
9771
|
+
" \"byteSize\": <int>,",
|
|
9772
|
+
" \"entriesRendered\": <int>,",
|
|
9202
9773
|
" \"summary\": \"<1-3 sentence recap>\"",
|
|
9203
9774
|
"}",
|
|
9204
9775
|
"```",
|
|
@@ -9208,11 +9779,11 @@ function buildRenderPackPrompt(input, ctx) {
|
|
|
9208
9779
|
//#endregion
|
|
9209
9780
|
//#region ../agent-runtime/src/prompts/index.ts
|
|
9210
9781
|
/**
|
|
9211
|
-
* Resolve the correct prompt builder for `task.
|
|
9782
|
+
* Resolve the correct prompt builder for `task.taskType` and invoke it.
|
|
9212
9783
|
* Throws if the type is unknown or the input fails TypeBox validation.
|
|
9213
9784
|
*/
|
|
9214
9785
|
function buildPromptForTask(task, ctx) {
|
|
9215
|
-
switch (task.
|
|
9786
|
+
switch (task.taskType) {
|
|
9216
9787
|
case FULFILL_BRIEF_TYPE:
|
|
9217
9788
|
if (!Value.Check(FulfillBriefInput, task.input)) {
|
|
9218
9789
|
const errors = [...Value.Errors(FulfillBriefInput, task.input)];
|
|
@@ -9262,9 +9833,101 @@ function buildPromptForTask(task, ctx) {
|
|
|
9262
9833
|
diaryId: ctx.diaryId,
|
|
9263
9834
|
taskId: ctx.taskId
|
|
9264
9835
|
});
|
|
9265
|
-
default: throw new Error(`No prompt builder registered for
|
|
9836
|
+
default: throw new Error(`No prompt builder registered for taskType="${task.taskType}"`);
|
|
9837
|
+
}
|
|
9838
|
+
}
|
|
9839
|
+
//#endregion
|
|
9840
|
+
//#region src/runtime/task-output.ts
|
|
9841
|
+
async function parseStructuredTaskOutput(assistantText, taskType) {
|
|
9842
|
+
const extracted = extractJsonObject(assistantText);
|
|
9843
|
+
if (!extracted) return {
|
|
9844
|
+
output: null,
|
|
9845
|
+
outputCid: null,
|
|
9846
|
+
error: {
|
|
9847
|
+
code: "output_missing",
|
|
9848
|
+
message: "Agent did not emit a parseable JSON object as its final message."
|
|
9849
|
+
}
|
|
9850
|
+
};
|
|
9851
|
+
const errors = validateTaskOutput(taskType, extracted);
|
|
9852
|
+
if (errors.length > 0) {
|
|
9853
|
+
const details = errors.slice(0, 3).map((error) => `${error.field}: ${error.message}`);
|
|
9854
|
+
const [firstError] = errors;
|
|
9855
|
+
return {
|
|
9856
|
+
output: null,
|
|
9857
|
+
outputCid: null,
|
|
9858
|
+
error: {
|
|
9859
|
+
code: firstError?.field === "taskType" ? "unknown_task_type" : "output_validation_failed",
|
|
9860
|
+
message: `Output failed schema validation: ${details.join("; ")}`
|
|
9861
|
+
}
|
|
9862
|
+
};
|
|
9863
|
+
}
|
|
9864
|
+
try {
|
|
9865
|
+
return {
|
|
9866
|
+
output: extracted,
|
|
9867
|
+
outputCid: await computeJsonCid(extracted),
|
|
9868
|
+
error: null
|
|
9869
|
+
};
|
|
9870
|
+
} catch (error) {
|
|
9871
|
+
return {
|
|
9872
|
+
output: null,
|
|
9873
|
+
outputCid: null,
|
|
9874
|
+
error: {
|
|
9875
|
+
code: "output_cid_compute_failed",
|
|
9876
|
+
message: `Validated output could not be canonicalized: ${error instanceof Error ? error.message : String(error)}`
|
|
9877
|
+
}
|
|
9878
|
+
};
|
|
9266
9879
|
}
|
|
9267
9880
|
}
|
|
9881
|
+
/**
|
|
9882
|
+
* Find the last balanced top-level JSON object in `text` and parse it.
|
|
9883
|
+
* Tolerates markdown fences and leading prose. Returns null if parsing fails.
|
|
9884
|
+
*/
|
|
9885
|
+
function extractJsonObject(text) {
|
|
9886
|
+
if (!text) return null;
|
|
9887
|
+
const fenceMatch = /```(?:json)?\s*([\s\S]*?)```/gi;
|
|
9888
|
+
const candidates = [];
|
|
9889
|
+
for (const m of text.matchAll(fenceMatch)) candidates.push(m[1]);
|
|
9890
|
+
const scanForObject = (s) => {
|
|
9891
|
+
let depth = 0;
|
|
9892
|
+
let start = -1;
|
|
9893
|
+
let lastComplete = null;
|
|
9894
|
+
let inString = false;
|
|
9895
|
+
let escape = false;
|
|
9896
|
+
for (let i = 0; i < s.length; i++) {
|
|
9897
|
+
const ch = s[i];
|
|
9898
|
+
if (inString) {
|
|
9899
|
+
if (escape) escape = false;
|
|
9900
|
+
else if (ch === "\\") escape = true;
|
|
9901
|
+
else if (ch === "\"") inString = false;
|
|
9902
|
+
continue;
|
|
9903
|
+
}
|
|
9904
|
+
if (ch === "\"") {
|
|
9905
|
+
inString = true;
|
|
9906
|
+
continue;
|
|
9907
|
+
}
|
|
9908
|
+
if (ch === "{") {
|
|
9909
|
+
if (depth === 0) start = i;
|
|
9910
|
+
depth++;
|
|
9911
|
+
} else if (ch === "}") {
|
|
9912
|
+
depth--;
|
|
9913
|
+
if (depth === 0 && start !== -1) {
|
|
9914
|
+
lastComplete = s.slice(start, i + 1);
|
|
9915
|
+
start = -1;
|
|
9916
|
+
}
|
|
9917
|
+
}
|
|
9918
|
+
}
|
|
9919
|
+
return lastComplete;
|
|
9920
|
+
};
|
|
9921
|
+
candidates.push(text);
|
|
9922
|
+
for (let i = candidates.length - 1; i >= 0; i--) {
|
|
9923
|
+
const obj = scanForObject(candidates[i]);
|
|
9924
|
+
if (!obj) continue;
|
|
9925
|
+
try {
|
|
9926
|
+
return JSON.parse(obj);
|
|
9927
|
+
} catch {}
|
|
9928
|
+
}
|
|
9929
|
+
return null;
|
|
9930
|
+
}
|
|
9268
9931
|
//#endregion
|
|
9269
9932
|
//#region src/runtime/execute-pi-task.ts
|
|
9270
9933
|
/**
|
|
@@ -9290,14 +9953,14 @@ function buildPromptForTask(task, ctx) {
|
|
|
9290
9953
|
*/
|
|
9291
9954
|
function createPiTaskExecutor(opts) {
|
|
9292
9955
|
let cachedCheckpoint = opts.checkpointPath ?? null;
|
|
9293
|
-
return async (
|
|
9956
|
+
return async (claimedTask, reporter) => {
|
|
9294
9957
|
if (!cachedCheckpoint) cachedCheckpoint = await ensureSnapshot({
|
|
9295
9958
|
config: opts.sandboxConfig?.snapshot,
|
|
9296
9959
|
onProgress: opts.onSnapshotProgress ?? ((m) => {
|
|
9297
9960
|
process.stderr.write(`[snapshot] ${m}\n`);
|
|
9298
9961
|
})
|
|
9299
9962
|
});
|
|
9300
|
-
return executePiTask(
|
|
9963
|
+
return executePiTask(claimedTask, reporter, {
|
|
9301
9964
|
...opts,
|
|
9302
9965
|
checkpointPath: cachedCheckpoint
|
|
9303
9966
|
});
|
|
@@ -9309,8 +9972,9 @@ function createPiTaskExecutor(opts) {
|
|
|
9309
9972
|
* a `TaskOutput` (failures surface as `status: 'failed'`); throws only on
|
|
9310
9973
|
* unrecoverable setup errors.
|
|
9311
9974
|
*/
|
|
9312
|
-
async function executePiTask(
|
|
9313
|
-
const
|
|
9975
|
+
async function executePiTask(claimedTask, reporter, opts) {
|
|
9976
|
+
const task = claimedTask.task;
|
|
9977
|
+
const attemptN = claimedTask.attemptN;
|
|
9314
9978
|
const startTime = Date.now();
|
|
9315
9979
|
const mountPath = opts.mountPath ?? process.cwd();
|
|
9316
9980
|
const checkpointPath = opts.checkpointPath ?? await ensureSnapshot({
|
|
@@ -9336,17 +10000,18 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9336
10000
|
extraAllowedHosts: opts.extraAllowedHosts,
|
|
9337
10001
|
sandboxConfig: opts.sandboxConfig
|
|
9338
10002
|
});
|
|
9339
|
-
const diaryId = task.
|
|
10003
|
+
const diaryId = task.diaryId ?? "";
|
|
9340
10004
|
let reporterOpen = false;
|
|
9341
10005
|
let session = null;
|
|
9342
|
-
const
|
|
9343
|
-
|
|
9344
|
-
|
|
10006
|
+
const finalUsage = emptyUsage(opts.provider, opts.model);
|
|
10007
|
+
const makeFailedOutput = (code, message, usage = finalUsage) => ({
|
|
10008
|
+
taskId: task.id,
|
|
10009
|
+
attemptN,
|
|
9345
10010
|
status: "failed",
|
|
9346
10011
|
output: null,
|
|
9347
|
-
|
|
10012
|
+
outputCid: null,
|
|
9348
10013
|
usage,
|
|
9349
|
-
|
|
10014
|
+
durationMs: Date.now() - startTime,
|
|
9350
10015
|
error: {
|
|
9351
10016
|
code,
|
|
9352
10017
|
message,
|
|
@@ -9367,8 +10032,8 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9367
10032
|
});
|
|
9368
10033
|
await emit("info", {
|
|
9369
10034
|
event: "execute_start",
|
|
9370
|
-
|
|
9371
|
-
|
|
10035
|
+
taskType: task.taskType,
|
|
10036
|
+
teamId: task.teamId,
|
|
9372
10037
|
provider: opts.provider,
|
|
9373
10038
|
model: opts.model
|
|
9374
10039
|
});
|
|
@@ -9399,7 +10064,9 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9399
10064
|
getAgent: () => moltnetAgent,
|
|
9400
10065
|
getDiaryId: () => diaryId,
|
|
9401
10066
|
getSessionErrors: () => [],
|
|
9402
|
-
clearSessionErrors: () => {}
|
|
10067
|
+
clearSessionErrors: () => {},
|
|
10068
|
+
getHostCwd: () => mountPath,
|
|
10069
|
+
hostExecBaseEnv: new Set([...HOST_EXEC_DEFAULT_BASE_ENV, ...Object.keys(managed.credentials.agentEnv)])
|
|
9403
10070
|
});
|
|
9404
10071
|
const piAuthDir = join(homedir(), ".pi", "agent");
|
|
9405
10072
|
const modelHandle = getModel(opts.provider, opts.model);
|
|
@@ -9427,7 +10094,7 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9427
10094
|
let llmAbort = false;
|
|
9428
10095
|
let assistantText = "";
|
|
9429
10096
|
let reporterError = null;
|
|
9430
|
-
const usage =
|
|
10097
|
+
const usage = finalUsage;
|
|
9431
10098
|
const recordingPromise = [];
|
|
9432
10099
|
const track = (p) => {
|
|
9433
10100
|
recordingPromise.push(p.catch((err) => {
|
|
@@ -9457,12 +10124,12 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9457
10124
|
else if (event.type === "turn_end") {
|
|
9458
10125
|
const msg = event.message;
|
|
9459
10126
|
if (msg?.role === "assistant" && msg.usage) {
|
|
9460
|
-
usage.
|
|
9461
|
-
usage.
|
|
10127
|
+
usage.inputTokens += Math.max(0, msg.usage.input ?? 0);
|
|
10128
|
+
usage.outputTokens += Math.max(0, msg.usage.output ?? 0);
|
|
9462
10129
|
const cr = Math.max(0, msg.usage.cacheRead ?? 0);
|
|
9463
10130
|
const cw = Math.max(0, msg.usage.cacheWrite ?? 0);
|
|
9464
|
-
if (cr) usage.
|
|
9465
|
-
if (cw) usage.
|
|
10131
|
+
if (cr) usage.cacheReadTokens = (usage.cacheReadTokens ?? 0) + cr;
|
|
10132
|
+
if (cw) usage.cacheWriteTokens = (usage.cacheWriteTokens ?? 0) + cw;
|
|
9466
10133
|
}
|
|
9467
10134
|
track(emit("turn_end", { stop_reason: msg?.stopReason ?? "end_turn" }));
|
|
9468
10135
|
llmAbort = msg?.stopReason === "error";
|
|
@@ -9484,28 +10151,13 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9484
10151
|
}
|
|
9485
10152
|
await Promise.all(recordingPromise);
|
|
9486
10153
|
let parsedOutput = null;
|
|
10154
|
+
let parsedOutputCid = null;
|
|
9487
10155
|
let parseError = null;
|
|
9488
10156
|
if (!runError && !llmAbort) {
|
|
9489
|
-
const
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
};
|
|
9494
|
-
else {
|
|
9495
|
-
const entry = BUILT_IN_TASK_TYPES[task.task_type];
|
|
9496
|
-
if (!entry) parseError = {
|
|
9497
|
-
code: "unknown_task_type",
|
|
9498
|
-
message: `No output schema registered for task_type=${task.task_type}`
|
|
9499
|
-
};
|
|
9500
|
-
else {
|
|
9501
|
-
const check = TypeCompiler.Compile(entry.outputSchema);
|
|
9502
|
-
if (check.Check(extracted)) parsedOutput = extracted;
|
|
9503
|
-
else parseError = {
|
|
9504
|
-
code: "output_validation_failed",
|
|
9505
|
-
message: `Output failed schema validation: ${[...check.Errors(extracted)].slice(0, 3).map((e) => `${e.path}: ${e.message}`).join("; ")}`
|
|
9506
|
-
};
|
|
9507
|
-
}
|
|
9508
|
-
}
|
|
10157
|
+
const parsed = await parseStructuredTaskOutput(assistantText, task.taskType);
|
|
10158
|
+
parsedOutput = parsed.output;
|
|
10159
|
+
parsedOutputCid = parsed.outputCid;
|
|
10160
|
+
parseError = parsed.error;
|
|
9509
10161
|
if (parseError) await emit("error", {
|
|
9510
10162
|
message: parseError.message,
|
|
9511
10163
|
phase: "output_validation"
|
|
@@ -9515,13 +10167,13 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9515
10167
|
const errorCode = runError?.code ?? parseError?.code ?? reporterError?.code ?? (llmAbort ? "llm_api_error" : void 0);
|
|
9516
10168
|
const errorMessage = runError?.message ?? parseError?.message ?? reporterError?.message ?? (llmAbort ? "LLM API error during turn" : void 0);
|
|
9517
10169
|
return {
|
|
9518
|
-
|
|
9519
|
-
|
|
10170
|
+
taskId: task.id,
|
|
10171
|
+
attemptN,
|
|
9520
10172
|
status,
|
|
9521
10173
|
output: parsedOutput,
|
|
9522
|
-
|
|
10174
|
+
outputCid: parsedOutputCid,
|
|
9523
10175
|
usage,
|
|
9524
|
-
|
|
10176
|
+
durationMs: Date.now() - startTime,
|
|
9525
10177
|
...errorCode && errorMessage ? { error: {
|
|
9526
10178
|
code: errorCode,
|
|
9527
10179
|
message: errorMessage,
|
|
@@ -9536,7 +10188,7 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9536
10188
|
} catch {}
|
|
9537
10189
|
if (reporterOpen) {
|
|
9538
10190
|
try {
|
|
9539
|
-
await reporter.finalize(
|
|
10191
|
+
await reporter.finalize(finalUsage);
|
|
9540
10192
|
} catch {}
|
|
9541
10193
|
try {
|
|
9542
10194
|
await reporter.close();
|
|
@@ -9547,8 +10199,8 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9547
10199
|
}
|
|
9548
10200
|
function emptyUsage(provider, model) {
|
|
9549
10201
|
return {
|
|
9550
|
-
|
|
9551
|
-
|
|
10202
|
+
inputTokens: 0,
|
|
10203
|
+
outputTokens: 0,
|
|
9552
10204
|
provider,
|
|
9553
10205
|
model
|
|
9554
10206
|
};
|
|
@@ -9582,79 +10234,16 @@ function truncateForWire(value) {
|
|
|
9582
10234
|
};
|
|
9583
10235
|
}
|
|
9584
10236
|
}
|
|
9585
|
-
/**
|
|
9586
|
-
* Find the last balanced top-level JSON object in `text` and parse it.
|
|
9587
|
-
* Tolerates markdown fences and leading prose. Returns null if parsing fails.
|
|
9588
|
-
*/
|
|
9589
|
-
function extractJsonObject(text) {
|
|
9590
|
-
if (!text) return null;
|
|
9591
|
-
const fenceMatch = /```(?:json)?\s*([\s\S]*?)```/gi;
|
|
9592
|
-
const candidates = [];
|
|
9593
|
-
for (const m of text.matchAll(fenceMatch)) candidates.push(m[1]);
|
|
9594
|
-
const scanForObject = (s) => {
|
|
9595
|
-
let depth = 0;
|
|
9596
|
-
let start = -1;
|
|
9597
|
-
let lastComplete = null;
|
|
9598
|
-
let inString = false;
|
|
9599
|
-
let escape = false;
|
|
9600
|
-
for (let i = 0; i < s.length; i++) {
|
|
9601
|
-
const ch = s[i];
|
|
9602
|
-
if (inString) {
|
|
9603
|
-
if (escape) escape = false;
|
|
9604
|
-
else if (ch === "\\") escape = true;
|
|
9605
|
-
else if (ch === "\"") inString = false;
|
|
9606
|
-
continue;
|
|
9607
|
-
}
|
|
9608
|
-
if (ch === "\"") {
|
|
9609
|
-
inString = true;
|
|
9610
|
-
continue;
|
|
9611
|
-
}
|
|
9612
|
-
if (ch === "{") {
|
|
9613
|
-
if (depth === 0) start = i;
|
|
9614
|
-
depth++;
|
|
9615
|
-
} else if (ch === "}") {
|
|
9616
|
-
depth--;
|
|
9617
|
-
if (depth === 0 && start !== -1) {
|
|
9618
|
-
lastComplete = s.slice(start, i + 1);
|
|
9619
|
-
start = -1;
|
|
9620
|
-
}
|
|
9621
|
-
}
|
|
9622
|
-
}
|
|
9623
|
-
return lastComplete;
|
|
9624
|
-
};
|
|
9625
|
-
candidates.push(text);
|
|
9626
|
-
for (let i = candidates.length - 1; i >= 0; i--) {
|
|
9627
|
-
const obj = scanForObject(candidates[i]);
|
|
9628
|
-
if (!obj) continue;
|
|
9629
|
-
try {
|
|
9630
|
-
return JSON.parse(obj);
|
|
9631
|
-
} catch {}
|
|
9632
|
-
}
|
|
9633
|
-
return null;
|
|
9634
|
-
}
|
|
9635
10237
|
//#endregion
|
|
9636
10238
|
//#region src/index.ts
|
|
9637
10239
|
/**
|
|
9638
10240
|
* @themoltnet/pi-extension — MoltNet pi extension
|
|
9639
10241
|
*
|
|
9640
|
-
*
|
|
9641
|
-
*
|
|
9642
|
-
* - Credential injection (pi OAuth + MoltNet identity)
|
|
9643
|
-
* - Egress policy (only LLM provider + MoltNet API)
|
|
9644
|
-
* - Tool redirection (read/write/edit/bash → VM)
|
|
9645
|
-
* - MoltNet custom tools (diary entries — run on host via SDK)
|
|
9646
|
-
* - Optional git worktree per session
|
|
10242
|
+
* Runs pi coding-agent sessions inside a Gondolin VM with the agent's
|
|
10243
|
+
* MoltNet identity fully available inside the sandbox.
|
|
9647
10244
|
*
|
|
9648
|
-
*
|
|
9649
|
-
*
|
|
9650
|
-
* pi -e @themoltnet/pi-extension --agent legreffier
|
|
9651
|
-
* pi -e @themoltnet/pi-extension --worktree-branch feat/my-task
|
|
9652
|
-
* pi -e @themoltnet/pi-extension --sandbox-config ./sandbox.json
|
|
9653
|
-
*
|
|
9654
|
-
* Sandbox config resolution (first match):
|
|
9655
|
-
* 1. --sandbox-config flag (explicit path to JSON)
|
|
9656
|
-
* 2. sandbox.json in cwd (convention)
|
|
9657
|
-
* 3. Base only (git, gh, moltnet CLI, agent user)
|
|
10245
|
+
* See README.md for credential injection flow, tool split, sandbox.json
|
|
10246
|
+
* reference, and headless/programmatic usage.
|
|
9658
10247
|
*/
|
|
9659
10248
|
var GUEST_WORKSPACE = "/workspace";
|
|
9660
10249
|
function moltnetExtension(pi) {
|
|
@@ -9692,6 +10281,7 @@ function moltnetExtension(pi) {
|
|
|
9692
10281
|
let worktreePath = null;
|
|
9693
10282
|
let moltnetAgent = null;
|
|
9694
10283
|
let diaryId = null;
|
|
10284
|
+
let hostExecBaseEnv = HOST_EXEC_DEFAULT_BASE_ENV;
|
|
9695
10285
|
async function ensureVm(ctx) {
|
|
9696
10286
|
if (vm) return vm;
|
|
9697
10287
|
if (vmStarting) return vmStarting;
|
|
@@ -9745,6 +10335,7 @@ function moltnetExtension(pi) {
|
|
|
9745
10335
|
activateAgentEnv(managed.credentials.agentEnv, mainRepo);
|
|
9746
10336
|
moltnetAgent = await connect({ configDir: managed.agentDir });
|
|
9747
10337
|
diaryId = managed.credentials.agentEnv.MOLTNET_DIARY_ID ?? null;
|
|
10338
|
+
hostExecBaseEnv = new Set([...HOST_EXEC_DEFAULT_BASE_ENV, ...Object.keys(managed.credentials.agentEnv)]);
|
|
9748
10339
|
vm = managed.vm;
|
|
9749
10340
|
const label = worktreePath ? `${mountPath} → ${GUEST_WORKSPACE}` : `${localCwd} → ${GUEST_WORKSPACE}`;
|
|
9750
10341
|
ctx?.ui.setStatus("sandbox", ctx.ui.theme.fg("accent", `Sandbox: running (${label})`));
|
|
@@ -9807,7 +10398,9 @@ function moltnetExtension(pi) {
|
|
|
9807
10398
|
getSessionErrors: () => sessionErrors,
|
|
9808
10399
|
clearSessionErrors: () => {
|
|
9809
10400
|
sessionErrors.length = 0;
|
|
9810
|
-
}
|
|
10401
|
+
},
|
|
10402
|
+
getHostCwd: () => worktreePath ?? localCwd,
|
|
10403
|
+
hostExecBaseEnv
|
|
9811
10404
|
});
|
|
9812
10405
|
for (const tool of moltnetTools) pi.registerTool(tool);
|
|
9813
10406
|
const sessionStartTime = Date.now();
|
|
@@ -9913,4 +10506,4 @@ function moltnetExtension(pi) {
|
|
|
9913
10506
|
registerMoltnetReflectCommand(pi, state);
|
|
9914
10507
|
}
|
|
9915
10508
|
//#endregion
|
|
9916
|
-
export { activateAgentEnv, buildPiJudgeRecipeManifest, computePiJudgeRecipeCid, createGondolinBashOps, createGondolinEditOps, createGondolinReadOps, createGondolinWriteOps, createMoltNetTools, createPiTaskExecutor, moltnetExtension as default, ensureSnapshot, executePiTask, findMainWorktree, loadCredentials, resolvePiJudgeRecipeVersions, resumeVm, toGuestPath };
|
|
10509
|
+
export { HOST_EXEC_DEFAULT_BASE_ENV, activateAgentEnv, buildPiJudgeRecipeManifest, computePiJudgeRecipeCid, createGondolinBashOps, createGondolinEditOps, createGondolinReadOps, createGondolinWriteOps, createMoltNetTools, createPiTaskExecutor, moltnetExtension as default, ensureSnapshot, executePiTask, findMainWorktree, loadCredentials, resolvePiJudgeRecipeVersions, resumeVm, toGuestPath };
|