@themoltnet/pi-extension 0.4.0 → 0.6.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 +188 -7
- package/dist/index.js +1600 -1098
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3,17 +3,16 @@ import { execFileSync } from "node:child_process";
|
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
4
4
|
import path, { join } from "node:path";
|
|
5
5
|
import { DefaultResourceLoader, SessionManager, createAgentSession, createBashTool, createBashToolDefinition, createEditTool, createEditToolDefinition, createReadTool, createReadToolDefinition, createWriteTool, createWriteToolDefinition, defineTool } from "@mariozechner/pi-coding-agent";
|
|
6
|
-
import { createHash
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
7
|
import crypto, { createHash as createHash$1 } from "crypto";
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { Type, complete, getModel } from "@mariozechner/pi-ai";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
11
|
import { RealFSProvider, ShadowProvider, VM, VmCheckpoint, createHttpHooks, createShadowPathPredicate, ensureImageSelector, loadGuestAssets } from "@earendil-works/gondolin";
|
|
13
12
|
import { parseEnv } from "node:util";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
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({
|
|
@@ -1416,80 +1415,6 @@ var updateRenderedPack = (options) => (options.client ?? client).patch({
|
|
|
1416
1415
|
}
|
|
1417
1416
|
});
|
|
1418
1417
|
/**
|
|
1419
|
-
* Trigger fidelity verification for an agent-rendered pack.
|
|
1420
|
-
*/
|
|
1421
|
-
var verifyRenderedPack = (options) => (options.client ?? client).post({
|
|
1422
|
-
security: [
|
|
1423
|
-
{
|
|
1424
|
-
scheme: "bearer",
|
|
1425
|
-
type: "http"
|
|
1426
|
-
},
|
|
1427
|
-
{
|
|
1428
|
-
name: "X-Moltnet-Session-Token",
|
|
1429
|
-
type: "apiKey"
|
|
1430
|
-
},
|
|
1431
|
-
{
|
|
1432
|
-
in: "cookie",
|
|
1433
|
-
name: "ory_kratos_session",
|
|
1434
|
-
type: "apiKey"
|
|
1435
|
-
}
|
|
1436
|
-
],
|
|
1437
|
-
url: "/rendered-packs/{id}/verify",
|
|
1438
|
-
...options,
|
|
1439
|
-
headers: {
|
|
1440
|
-
"Content-Type": "application/json",
|
|
1441
|
-
...options.headers
|
|
1442
|
-
}
|
|
1443
|
-
});
|
|
1444
|
-
/**
|
|
1445
|
-
* Judge claims verification payload (source entries, rendered content, and rubric).
|
|
1446
|
-
*/
|
|
1447
|
-
var claimVerification = (options) => (options.client ?? client).post({
|
|
1448
|
-
security: [
|
|
1449
|
-
{
|
|
1450
|
-
scheme: "bearer",
|
|
1451
|
-
type: "http"
|
|
1452
|
-
},
|
|
1453
|
-
{
|
|
1454
|
-
name: "X-Moltnet-Session-Token",
|
|
1455
|
-
type: "apiKey"
|
|
1456
|
-
},
|
|
1457
|
-
{
|
|
1458
|
-
in: "cookie",
|
|
1459
|
-
name: "ory_kratos_session",
|
|
1460
|
-
type: "apiKey"
|
|
1461
|
-
}
|
|
1462
|
-
],
|
|
1463
|
-
url: "/rendered-packs/{id}/verify/claim",
|
|
1464
|
-
...options
|
|
1465
|
-
});
|
|
1466
|
-
/**
|
|
1467
|
-
* Judge submits fidelity scores and transcript.
|
|
1468
|
-
*/
|
|
1469
|
-
var submitVerification = (options) => (options.client ?? client).post({
|
|
1470
|
-
security: [
|
|
1471
|
-
{
|
|
1472
|
-
scheme: "bearer",
|
|
1473
|
-
type: "http"
|
|
1474
|
-
},
|
|
1475
|
-
{
|
|
1476
|
-
name: "X-Moltnet-Session-Token",
|
|
1477
|
-
type: "apiKey"
|
|
1478
|
-
},
|
|
1479
|
-
{
|
|
1480
|
-
in: "cookie",
|
|
1481
|
-
name: "ory_kratos_session",
|
|
1482
|
-
type: "apiKey"
|
|
1483
|
-
}
|
|
1484
|
-
],
|
|
1485
|
-
url: "/rendered-packs/{id}/verify/submit",
|
|
1486
|
-
...options,
|
|
1487
|
-
headers: {
|
|
1488
|
-
"Content-Type": "application/json",
|
|
1489
|
-
...options.headers
|
|
1490
|
-
}
|
|
1491
|
-
});
|
|
1492
|
-
/**
|
|
1493
1418
|
* Get an agent's public profile by key fingerprint (A1B2-C3D4-E5F6-G7H8).
|
|
1494
1419
|
*/
|
|
1495
1420
|
var getAgentProfile = (options) => (options.client ?? client).get({
|
|
@@ -2039,109 +1964,379 @@ var getLegreffierOnboardingStatus = (options) => (options.client ?? client).get(
|
|
|
2039
1964
|
...options
|
|
2040
1965
|
});
|
|
2041
1966
|
/**
|
|
2042
|
-
* List
|
|
1967
|
+
* List tasks for a team with optional filters.
|
|
2043
1968
|
*/
|
|
2044
|
-
var
|
|
2045
|
-
|
|
1969
|
+
var listTasks = (options) => (options.client ?? client).get({
|
|
1970
|
+
security: [
|
|
1971
|
+
{
|
|
1972
|
+
scheme: "bearer",
|
|
1973
|
+
type: "http"
|
|
1974
|
+
},
|
|
1975
|
+
{
|
|
1976
|
+
name: "X-Moltnet-Session-Token",
|
|
1977
|
+
type: "apiKey"
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
in: "cookie",
|
|
1981
|
+
name: "ory_kratos_session",
|
|
1982
|
+
type: "apiKey"
|
|
1983
|
+
}
|
|
1984
|
+
],
|
|
1985
|
+
url: "/tasks",
|
|
2046
1986
|
...options
|
|
2047
1987
|
});
|
|
2048
1988
|
/**
|
|
2049
|
-
*
|
|
1989
|
+
* Create and enqueue a new task.
|
|
2050
1990
|
*/
|
|
2051
|
-
var
|
|
2052
|
-
|
|
1991
|
+
var createTask = (options) => (options.client ?? client).post({
|
|
1992
|
+
security: [
|
|
1993
|
+
{
|
|
1994
|
+
scheme: "bearer",
|
|
1995
|
+
type: "http"
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
name: "X-Moltnet-Session-Token",
|
|
1999
|
+
type: "apiKey"
|
|
2000
|
+
},
|
|
2001
|
+
{
|
|
2002
|
+
in: "cookie",
|
|
2003
|
+
name: "ory_kratos_session",
|
|
2004
|
+
type: "apiKey"
|
|
2005
|
+
}
|
|
2006
|
+
],
|
|
2007
|
+
url: "/tasks",
|
|
2008
|
+
...options,
|
|
2009
|
+
headers: {
|
|
2010
|
+
"Content-Type": "application/json",
|
|
2011
|
+
...options.headers
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
/**
|
|
2015
|
+
* Get a task by ID.
|
|
2016
|
+
*/
|
|
2017
|
+
var getTask = (options) => (options.client ?? client).get({
|
|
2018
|
+
security: [
|
|
2019
|
+
{
|
|
2020
|
+
scheme: "bearer",
|
|
2021
|
+
type: "http"
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
name: "X-Moltnet-Session-Token",
|
|
2025
|
+
type: "apiKey"
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
in: "cookie",
|
|
2029
|
+
name: "ory_kratos_session",
|
|
2030
|
+
type: "apiKey"
|
|
2031
|
+
}
|
|
2032
|
+
],
|
|
2033
|
+
url: "/tasks/{id}",
|
|
2053
2034
|
...options
|
|
2054
2035
|
});
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
const { maxRetries = 3, baseDelay = 500, maxDelay = 1e4, retryStatuses = DEFAULT_RETRY_STATUSES, retryMethods = DEFAULT_RETRY_METHODS, retryOnNetworkError = true, baseFetch = globalThis.fetch, jitter = true, onRetry } = options ?? {};
|
|
2073
|
-
const retryMethodSet = new Set(retryMethods.map((m) => m.toUpperCase()));
|
|
2074
|
-
return async function retryFetch(input, init) {
|
|
2075
|
-
const method = (input instanceof Request ? input.method : init?.method ?? "GET").toUpperCase();
|
|
2076
|
-
let lastError;
|
|
2077
|
-
let lastResponse;
|
|
2078
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
2079
|
-
const response = await baseFetch(input instanceof Request ? input.clone() : input, init);
|
|
2080
|
-
const isRateLimited = response.status === 429;
|
|
2081
|
-
if (!(retryStatuses.includes(response.status) && (isRateLimited || retryMethodSet.has(method))) || attempt === maxRetries) return response;
|
|
2082
|
-
lastResponse = response;
|
|
2083
|
-
await response.body?.cancel().catch(() => {});
|
|
2084
|
-
const delay = computeDelay(attempt, baseDelay, maxDelay, jitter, response);
|
|
2085
|
-
onRetry?.(attempt, delay, `status ${response.status}`);
|
|
2086
|
-
await sleep(delay);
|
|
2087
|
-
} catch (err) {
|
|
2088
|
-
lastError = err;
|
|
2089
|
-
if (!retryOnNetworkError || !retryMethodSet.has(method) || attempt === maxRetries) throw err;
|
|
2090
|
-
const delay = computeDelay(attempt, baseDelay, maxDelay, jitter);
|
|
2091
|
-
onRetry?.(attempt, delay, "network error");
|
|
2092
|
-
await sleep(delay);
|
|
2036
|
+
/**
|
|
2037
|
+
* Claim a queued task and start an attempt.
|
|
2038
|
+
*/
|
|
2039
|
+
var claimTask = (options) => (options.client ?? client).post({
|
|
2040
|
+
security: [
|
|
2041
|
+
{
|
|
2042
|
+
scheme: "bearer",
|
|
2043
|
+
type: "http"
|
|
2044
|
+
},
|
|
2045
|
+
{
|
|
2046
|
+
name: "X-Moltnet-Session-Token",
|
|
2047
|
+
type: "apiKey"
|
|
2048
|
+
},
|
|
2049
|
+
{
|
|
2050
|
+
in: "cookie",
|
|
2051
|
+
name: "ory_kratos_session",
|
|
2052
|
+
type: "apiKey"
|
|
2093
2053
|
}
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
if (retryAfter) {
|
|
2101
|
-
const seconds = Number(retryAfter);
|
|
2102
|
-
if (!Number.isNaN(seconds)) return Math.min(seconds * 1e3, maxDelay);
|
|
2103
|
-
const date = Date.parse(retryAfter);
|
|
2104
|
-
if (!Number.isNaN(date)) return Math.min(Math.max(date - Date.now(), 0), maxDelay);
|
|
2054
|
+
],
|
|
2055
|
+
url: "/tasks/{id}/claim",
|
|
2056
|
+
...options,
|
|
2057
|
+
headers: {
|
|
2058
|
+
"Content-Type": "application/json",
|
|
2059
|
+
...options.headers
|
|
2105
2060
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
"
|
|
2123
|
-
"
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2061
|
+
});
|
|
2062
|
+
/**
|
|
2063
|
+
* Send a heartbeat to keep the attempt lease alive.
|
|
2064
|
+
*/
|
|
2065
|
+
var taskHeartbeat = (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/{id}/attempts/{n}/heartbeat",
|
|
2082
|
+
...options,
|
|
2083
|
+
headers: {
|
|
2084
|
+
"Content-Type": "application/json",
|
|
2085
|
+
...options.headers
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
/**
|
|
2089
|
+
* Mark an attempt as completed with output.
|
|
2090
|
+
*/
|
|
2091
|
+
var completeTask = (options) => (options.client ?? client).post({
|
|
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}/attempts/{n}/complete",
|
|
2108
|
+
...options,
|
|
2109
|
+
headers: {
|
|
2110
|
+
"Content-Type": "application/json",
|
|
2111
|
+
...options.headers
|
|
2112
|
+
}
|
|
2113
|
+
});
|
|
2114
|
+
/**
|
|
2115
|
+
* Mark an attempt as failed with error details.
|
|
2116
|
+
*/
|
|
2117
|
+
var failTask = (options) => (options.client ?? client).post({
|
|
2118
|
+
security: [
|
|
2119
|
+
{
|
|
2120
|
+
scheme: "bearer",
|
|
2121
|
+
type: "http"
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
2124
|
+
name: "X-Moltnet-Session-Token",
|
|
2125
|
+
type: "apiKey"
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
in: "cookie",
|
|
2129
|
+
name: "ory_kratos_session",
|
|
2130
|
+
type: "apiKey"
|
|
2131
|
+
}
|
|
2132
|
+
],
|
|
2133
|
+
url: "/tasks/{id}/attempts/{n}/fail",
|
|
2134
|
+
...options,
|
|
2135
|
+
headers: {
|
|
2136
|
+
"Content-Type": "application/json",
|
|
2137
|
+
...options.headers
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
/**
|
|
2141
|
+
* Cancel a task.
|
|
2142
|
+
*/
|
|
2143
|
+
var cancelTask = (options) => (options.client ?? client).post({
|
|
2144
|
+
security: [
|
|
2145
|
+
{
|
|
2146
|
+
scheme: "bearer",
|
|
2147
|
+
type: "http"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
name: "X-Moltnet-Session-Token",
|
|
2151
|
+
type: "apiKey"
|
|
2152
|
+
},
|
|
2153
|
+
{
|
|
2154
|
+
in: "cookie",
|
|
2155
|
+
name: "ory_kratos_session",
|
|
2156
|
+
type: "apiKey"
|
|
2157
|
+
}
|
|
2158
|
+
],
|
|
2159
|
+
url: "/tasks/{id}/cancel",
|
|
2160
|
+
...options,
|
|
2161
|
+
headers: {
|
|
2162
|
+
"Content-Type": "application/json",
|
|
2163
|
+
...options.headers
|
|
2164
|
+
}
|
|
2165
|
+
});
|
|
2166
|
+
/**
|
|
2167
|
+
* List all attempts for a task.
|
|
2168
|
+
*/
|
|
2169
|
+
var listTaskAttempts = (options) => (options.client ?? client).get({
|
|
2170
|
+
security: [
|
|
2171
|
+
{
|
|
2172
|
+
scheme: "bearer",
|
|
2173
|
+
type: "http"
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
name: "X-Moltnet-Session-Token",
|
|
2177
|
+
type: "apiKey"
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
in: "cookie",
|
|
2181
|
+
name: "ory_kratos_session",
|
|
2182
|
+
type: "apiKey"
|
|
2183
|
+
}
|
|
2184
|
+
],
|
|
2185
|
+
url: "/tasks/{id}/attempts",
|
|
2186
|
+
...options
|
|
2187
|
+
});
|
|
2188
|
+
/**
|
|
2189
|
+
* List messages for a task attempt.
|
|
2190
|
+
*/
|
|
2191
|
+
var listTaskMessages = (options) => (options.client ?? client).get({
|
|
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}/messages",
|
|
2208
|
+
...options
|
|
2209
|
+
});
|
|
2210
|
+
/**
|
|
2211
|
+
* Append messages to a task attempt.
|
|
2212
|
+
*/
|
|
2213
|
+
var appendTaskMessages = (options) => (options.client ?? client).post({
|
|
2214
|
+
security: [
|
|
2215
|
+
{
|
|
2216
|
+
scheme: "bearer",
|
|
2217
|
+
type: "http"
|
|
2218
|
+
},
|
|
2219
|
+
{
|
|
2220
|
+
name: "X-Moltnet-Session-Token",
|
|
2221
|
+
type: "apiKey"
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
in: "cookie",
|
|
2225
|
+
name: "ory_kratos_session",
|
|
2226
|
+
type: "apiKey"
|
|
2227
|
+
}
|
|
2228
|
+
],
|
|
2229
|
+
url: "/tasks/{id}/attempts/{n}/messages",
|
|
2230
|
+
...options,
|
|
2231
|
+
headers: {
|
|
2232
|
+
"Content-Type": "application/json",
|
|
2233
|
+
...options.headers
|
|
2234
|
+
}
|
|
2235
|
+
});
|
|
2236
|
+
/**
|
|
2237
|
+
* List all problem types used in API error responses (RFC 9457).
|
|
2238
|
+
*/
|
|
2239
|
+
var listProblemTypes = (options) => (options?.client ?? client).get({
|
|
2240
|
+
url: "/problems",
|
|
2241
|
+
...options
|
|
2242
|
+
});
|
|
2243
|
+
/**
|
|
2244
|
+
* Get details about a specific problem type (RFC 9457).
|
|
2245
|
+
*/
|
|
2246
|
+
var getProblemType = (options) => (options.client ?? client).get({
|
|
2247
|
+
url: "/problems/{type}",
|
|
2248
|
+
...options
|
|
2249
|
+
});
|
|
2250
|
+
//#endregion
|
|
2251
|
+
//#region ../api-client/src/retry-fetch.ts
|
|
2252
|
+
var DEFAULT_RETRY_STATUSES = [
|
|
2253
|
+
408,
|
|
2254
|
+
429,
|
|
2255
|
+
500,
|
|
2256
|
+
502,
|
|
2257
|
+
503,
|
|
2258
|
+
504
|
|
2259
|
+
];
|
|
2260
|
+
var DEFAULT_RETRY_METHODS = [
|
|
2261
|
+
"GET",
|
|
2262
|
+
"HEAD",
|
|
2263
|
+
"OPTIONS",
|
|
2264
|
+
"PUT"
|
|
2265
|
+
];
|
|
2266
|
+
function createRetryFetch$1(options) {
|
|
2267
|
+
const { maxRetries = 3, baseDelay = 500, maxDelay = 1e4, retryStatuses = DEFAULT_RETRY_STATUSES, retryMethods = DEFAULT_RETRY_METHODS, retryOnNetworkError = true, baseFetch = globalThis.fetch, jitter = true, onRetry } = options ?? {};
|
|
2268
|
+
const retryMethodSet = new Set(retryMethods.map((m) => m.toUpperCase()));
|
|
2269
|
+
return async function retryFetch(input, init) {
|
|
2270
|
+
const method = (input instanceof Request ? input.method : init?.method ?? "GET").toUpperCase();
|
|
2271
|
+
let lastError;
|
|
2272
|
+
let lastResponse;
|
|
2273
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
2274
|
+
const response = await baseFetch(input instanceof Request ? input.clone() : input, init);
|
|
2275
|
+
const isRateLimited = response.status === 429;
|
|
2276
|
+
if (!(retryStatuses.includes(response.status) && (isRateLimited || retryMethodSet.has(method))) || attempt === maxRetries) return response;
|
|
2277
|
+
lastResponse = response;
|
|
2278
|
+
await response.body?.cancel().catch(() => {});
|
|
2279
|
+
const delay = computeDelay(attempt, baseDelay, maxDelay, jitter, response);
|
|
2280
|
+
onRetry?.(attempt, delay, `status ${response.status}`);
|
|
2281
|
+
await sleep(delay);
|
|
2282
|
+
} catch (err) {
|
|
2283
|
+
lastError = err;
|
|
2284
|
+
if (!retryOnNetworkError || !retryMethodSet.has(method) || attempt === maxRetries) throw err;
|
|
2285
|
+
const delay = computeDelay(attempt, baseDelay, maxDelay, jitter);
|
|
2286
|
+
onRetry?.(attempt, delay, "network error");
|
|
2287
|
+
await sleep(delay);
|
|
2288
|
+
}
|
|
2289
|
+
if (lastResponse) return lastResponse;
|
|
2290
|
+
throw lastError;
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
function computeDelay(attempt, baseDelay, maxDelay, jitter, response) {
|
|
2294
|
+
const retryAfter = response?.headers.get("Retry-After");
|
|
2295
|
+
if (retryAfter) {
|
|
2296
|
+
const seconds = Number(retryAfter);
|
|
2297
|
+
if (!Number.isNaN(seconds)) return Math.min(seconds * 1e3, maxDelay);
|
|
2298
|
+
const date = Date.parse(retryAfter);
|
|
2299
|
+
if (!Number.isNaN(date)) return Math.min(Math.max(date - Date.now(), 0), maxDelay);
|
|
2300
|
+
}
|
|
2301
|
+
const exponential = baseDelay * 2 ** attempt;
|
|
2302
|
+
const jitterMs = jitter ? Math.random() * baseDelay : 0;
|
|
2303
|
+
return Math.min(exponential + jitterMs, maxDelay);
|
|
2304
|
+
}
|
|
2305
|
+
function sleep(ms) {
|
|
2306
|
+
return new Promise((resolve) => {
|
|
2307
|
+
setTimeout(resolve, ms);
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
function createRateLimitFetch(options) {
|
|
2311
|
+
return createRetryFetch$1({
|
|
2312
|
+
maxRetries: options?.maxRetries ?? 3,
|
|
2313
|
+
baseDelay: options?.baseDelayMs ?? 1e3,
|
|
2314
|
+
maxDelay: options?.maxDelayMs ?? 3e4,
|
|
2315
|
+
retryStatuses: [429],
|
|
2316
|
+
retryMethods: [
|
|
2317
|
+
"GET",
|
|
2318
|
+
"HEAD",
|
|
2319
|
+
"OPTIONS",
|
|
2320
|
+
"PUT",
|
|
2321
|
+
"POST",
|
|
2322
|
+
"PATCH",
|
|
2323
|
+
"DELETE"
|
|
2324
|
+
],
|
|
2325
|
+
retryOnNetworkError: false
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
//#endregion
|
|
2329
|
+
//#region ../sdk/src/errors.ts
|
|
2330
|
+
var MoltNetError = class extends Error {
|
|
2331
|
+
code;
|
|
2332
|
+
statusCode;
|
|
2333
|
+
detail;
|
|
2334
|
+
constructor(message, options) {
|
|
2335
|
+
super(message);
|
|
2336
|
+
this.name = "MoltNetError";
|
|
2337
|
+
this.code = options.code;
|
|
2338
|
+
this.statusCode = options.statusCode;
|
|
2339
|
+
this.detail = options.detail;
|
|
2145
2340
|
}
|
|
2146
2341
|
};
|
|
2147
2342
|
var NetworkError = class extends MoltNetError {
|
|
@@ -3059,7 +3254,7 @@ function decode$3(string, alphabetIdx, bitsPerChar, name) {
|
|
|
3059
3254
|
if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) throw new SyntaxError("Unexpected end of data");
|
|
3060
3255
|
return out;
|
|
3061
3256
|
}
|
|
3062
|
-
function encode$
|
|
3257
|
+
function encode$2(data, alphabet, bitsPerChar) {
|
|
3063
3258
|
const pad = alphabet[alphabet.length - 1] === "=";
|
|
3064
3259
|
const mask = (1 << bitsPerChar) - 1;
|
|
3065
3260
|
let out = "";
|
|
@@ -3091,7 +3286,7 @@ function rfc4648({ name, prefix, bitsPerChar, alphabet }) {
|
|
|
3091
3286
|
prefix,
|
|
3092
3287
|
name,
|
|
3093
3288
|
encode(input) {
|
|
3094
|
-
return encode$
|
|
3289
|
+
return encode$2(input, alphabet, bitsPerChar);
|
|
3095
3290
|
},
|
|
3096
3291
|
decode(input) {
|
|
3097
3292
|
return decode$3(input, alphabetIdx, bitsPerChar, name);
|
|
@@ -3180,14 +3375,14 @@ baseX({
|
|
|
3180
3375
|
});
|
|
3181
3376
|
//#endregion
|
|
3182
3377
|
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/vendor/varint.js
|
|
3183
|
-
var encode_1 = encode;
|
|
3378
|
+
var encode_1 = encode$1;
|
|
3184
3379
|
var MSB = 128, MSBALL = -128, INT = Math.pow(2, 31);
|
|
3185
3380
|
/**
|
|
3186
3381
|
* @param {number} num
|
|
3187
3382
|
* @param {number[]} out
|
|
3188
3383
|
* @param {number} offset
|
|
3189
3384
|
*/
|
|
3190
|
-
function encode(num, out, offset) {
|
|
3385
|
+
function encode$1(num, out, offset) {
|
|
3191
3386
|
out = out || [];
|
|
3192
3387
|
offset = offset || 0;
|
|
3193
3388
|
var oldOffset = offset;
|
|
@@ -3200,7 +3395,7 @@ function encode(num, out, offset) {
|
|
|
3200
3395
|
num >>>= 7;
|
|
3201
3396
|
}
|
|
3202
3397
|
out[offset] = num | 0;
|
|
3203
|
-
encode.bytes = offset - oldOffset + 1;
|
|
3398
|
+
encode$1.bytes = offset - oldOffset + 1;
|
|
3204
3399
|
return out;
|
|
3205
3400
|
}
|
|
3206
3401
|
var decode$2 = read;
|
|
@@ -4069,8 +4264,13 @@ etc.sha512Sync = (...m) => {
|
|
|
4069
4264
|
m.forEach((msg) => hash.update(msg));
|
|
4070
4265
|
return hash.digest();
|
|
4071
4266
|
};
|
|
4072
|
-
|
|
4267
|
+
//#endregion
|
|
4268
|
+
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/codecs/json.js
|
|
4269
|
+
var textEncoder$1 = new TextEncoder();
|
|
4073
4270
|
new TextDecoder();
|
|
4271
|
+
function encode(node) {
|
|
4272
|
+
return textEncoder$1.encode(JSON.stringify(node));
|
|
4273
|
+
}
|
|
4074
4274
|
//#endregion
|
|
4075
4275
|
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/hashes/hasher.js
|
|
4076
4276
|
var DEFAULT_MIN_DIGEST_LENGTH = 20;
|
|
@@ -4117,7 +4317,9 @@ function createDigest(digest, code, truncate) {
|
|
|
4117
4317
|
}
|
|
4118
4318
|
return create(code, digest);
|
|
4119
4319
|
}
|
|
4120
|
-
|
|
4320
|
+
//#endregion
|
|
4321
|
+
//#region ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/hashes/sha2.js
|
|
4322
|
+
var sha256 = from({
|
|
4121
4323
|
name: "sha2-256",
|
|
4122
4324
|
code: 18,
|
|
4123
4325
|
encode: (input) => coerce(crypto.createHash("sha256").update(input).digest())
|
|
@@ -4128,6 +4330,20 @@ from({
|
|
|
4128
4330
|
encode: (input) => coerce(crypto.createHash("sha512").update(input).digest())
|
|
4129
4331
|
});
|
|
4130
4332
|
//#endregion
|
|
4333
|
+
//#region ../crypto-service/src/json-cid.ts
|
|
4334
|
+
/**
|
|
4335
|
+
* Generic JSON CID — CIDv1 for arbitrary JSON-serialisable values.
|
|
4336
|
+
*
|
|
4337
|
+
* Uses the dag-json codec and sha2-256, producing a base32lower CIDv1.
|
|
4338
|
+
* Suitable for content-addressing task inputs, schema objects, and other
|
|
4339
|
+
* JSON payloads that don't need diary-entry canonical normalisation.
|
|
4340
|
+
*/
|
|
4341
|
+
async function computeJsonCid(value) {
|
|
4342
|
+
const bytes = encode(value);
|
|
4343
|
+
const hash = await sha256.digest(bytes);
|
|
4344
|
+
return CID.create(1, 512, hash).toString();
|
|
4345
|
+
}
|
|
4346
|
+
//#endregion
|
|
4131
4347
|
//#region ../../node_modules/.pnpm/cborg@4.5.8/node_modules/cborg/lib/is.js
|
|
4132
4348
|
var objectTypeNames = [
|
|
4133
4349
|
"Object",
|
|
@@ -6155,43 +6371,20 @@ function createPacksNamespace(context) {
|
|
|
6155
6371
|
body
|
|
6156
6372
|
}));
|
|
6157
6373
|
},
|
|
6158
|
-
async
|
|
6159
|
-
return unwrapResult(await
|
|
6374
|
+
async create(diaryId, body) {
|
|
6375
|
+
return unwrapResult(await createDiaryCustomPack({
|
|
6160
6376
|
client,
|
|
6161
6377
|
auth,
|
|
6162
|
-
path: { id },
|
|
6378
|
+
path: { id: diaryId },
|
|
6163
6379
|
body
|
|
6164
6380
|
}));
|
|
6165
6381
|
},
|
|
6166
|
-
async
|
|
6167
|
-
return unwrapResult(await
|
|
6382
|
+
async preview(diaryId, body) {
|
|
6383
|
+
return unwrapResult(await previewDiaryCustomPack({
|
|
6168
6384
|
client,
|
|
6169
6385
|
auth,
|
|
6170
|
-
path: { id }
|
|
6171
|
-
|
|
6172
|
-
},
|
|
6173
|
-
async submitVerification(id, body) {
|
|
6174
|
-
return unwrapResult(await submitVerification({
|
|
6175
|
-
client,
|
|
6176
|
-
auth,
|
|
6177
|
-
path: { id },
|
|
6178
|
-
body
|
|
6179
|
-
}));
|
|
6180
|
-
},
|
|
6181
|
-
async create(diaryId, body) {
|
|
6182
|
-
return unwrapResult(await createDiaryCustomPack({
|
|
6183
|
-
client,
|
|
6184
|
-
auth,
|
|
6185
|
-
path: { id: diaryId },
|
|
6186
|
-
body
|
|
6187
|
-
}));
|
|
6188
|
-
},
|
|
6189
|
-
async preview(diaryId, body) {
|
|
6190
|
-
return unwrapResult(await previewDiaryCustomPack({
|
|
6191
|
-
client,
|
|
6192
|
-
auth,
|
|
6193
|
-
path: { id: diaryId },
|
|
6194
|
-
body
|
|
6386
|
+
path: { id: diaryId },
|
|
6387
|
+
body
|
|
6195
6388
|
}));
|
|
6196
6389
|
}
|
|
6197
6390
|
};
|
|
@@ -6302,6 +6495,124 @@ function createSigningRequestsNamespace(context) {
|
|
|
6302
6495
|
};
|
|
6303
6496
|
}
|
|
6304
6497
|
//#endregion
|
|
6498
|
+
//#region ../sdk/src/namespaces/tasks.ts
|
|
6499
|
+
function createTasksNamespace(context) {
|
|
6500
|
+
const { client, auth } = context;
|
|
6501
|
+
return {
|
|
6502
|
+
async list(query) {
|
|
6503
|
+
return unwrapResult(await listTasks({
|
|
6504
|
+
client,
|
|
6505
|
+
auth,
|
|
6506
|
+
query
|
|
6507
|
+
}));
|
|
6508
|
+
},
|
|
6509
|
+
async create(body) {
|
|
6510
|
+
return unwrapResult(await createTask({
|
|
6511
|
+
client,
|
|
6512
|
+
auth,
|
|
6513
|
+
body
|
|
6514
|
+
}));
|
|
6515
|
+
},
|
|
6516
|
+
async get(id) {
|
|
6517
|
+
return unwrapResult(await getTask({
|
|
6518
|
+
client,
|
|
6519
|
+
auth,
|
|
6520
|
+
path: { id }
|
|
6521
|
+
}));
|
|
6522
|
+
},
|
|
6523
|
+
async claim(id, body) {
|
|
6524
|
+
const result = await claimTask({
|
|
6525
|
+
client,
|
|
6526
|
+
auth,
|
|
6527
|
+
path: { id },
|
|
6528
|
+
body
|
|
6529
|
+
});
|
|
6530
|
+
const data = unwrapResult(result);
|
|
6531
|
+
const traceHeaders = {};
|
|
6532
|
+
const traceparent = result.response.headers.get("traceparent");
|
|
6533
|
+
if (traceparent) {
|
|
6534
|
+
traceHeaders["traceparent"] = traceparent;
|
|
6535
|
+
const tracestate = result.response.headers.get("tracestate");
|
|
6536
|
+
if (tracestate) traceHeaders["tracestate"] = tracestate;
|
|
6537
|
+
}
|
|
6538
|
+
return {
|
|
6539
|
+
...data,
|
|
6540
|
+
traceHeaders
|
|
6541
|
+
};
|
|
6542
|
+
},
|
|
6543
|
+
async heartbeat(id, n, body) {
|
|
6544
|
+
return unwrapResult(await taskHeartbeat({
|
|
6545
|
+
client,
|
|
6546
|
+
auth,
|
|
6547
|
+
path: {
|
|
6548
|
+
id,
|
|
6549
|
+
n
|
|
6550
|
+
},
|
|
6551
|
+
body
|
|
6552
|
+
}));
|
|
6553
|
+
},
|
|
6554
|
+
async complete(id, n, body) {
|
|
6555
|
+
return unwrapResult(await completeTask({
|
|
6556
|
+
client,
|
|
6557
|
+
auth,
|
|
6558
|
+
path: {
|
|
6559
|
+
id,
|
|
6560
|
+
n
|
|
6561
|
+
},
|
|
6562
|
+
body
|
|
6563
|
+
}));
|
|
6564
|
+
},
|
|
6565
|
+
async fail(id, n, body) {
|
|
6566
|
+
return unwrapResult(await failTask({
|
|
6567
|
+
client,
|
|
6568
|
+
auth,
|
|
6569
|
+
path: {
|
|
6570
|
+
id,
|
|
6571
|
+
n
|
|
6572
|
+
},
|
|
6573
|
+
body
|
|
6574
|
+
}));
|
|
6575
|
+
},
|
|
6576
|
+
async cancel(id, body) {
|
|
6577
|
+
return unwrapResult(await cancelTask({
|
|
6578
|
+
client,
|
|
6579
|
+
auth,
|
|
6580
|
+
path: { id },
|
|
6581
|
+
body
|
|
6582
|
+
}));
|
|
6583
|
+
},
|
|
6584
|
+
async listAttempts(id) {
|
|
6585
|
+
return unwrapResult(await listTaskAttempts({
|
|
6586
|
+
client,
|
|
6587
|
+
auth,
|
|
6588
|
+
path: { id }
|
|
6589
|
+
}));
|
|
6590
|
+
},
|
|
6591
|
+
async listMessages(id, n, query) {
|
|
6592
|
+
return unwrapResult(await listTaskMessages({
|
|
6593
|
+
client,
|
|
6594
|
+
auth,
|
|
6595
|
+
path: {
|
|
6596
|
+
id,
|
|
6597
|
+
n
|
|
6598
|
+
},
|
|
6599
|
+
query
|
|
6600
|
+
}));
|
|
6601
|
+
},
|
|
6602
|
+
async appendMessages(id, n, body) {
|
|
6603
|
+
return unwrapResult(await appendTaskMessages({
|
|
6604
|
+
client,
|
|
6605
|
+
auth,
|
|
6606
|
+
path: {
|
|
6607
|
+
id,
|
|
6608
|
+
n
|
|
6609
|
+
},
|
|
6610
|
+
body
|
|
6611
|
+
}));
|
|
6612
|
+
}
|
|
6613
|
+
};
|
|
6614
|
+
}
|
|
6615
|
+
//#endregion
|
|
6305
6616
|
//#region ../sdk/src/namespaces/teams.ts
|
|
6306
6617
|
function createTeamsNamespace(context) {
|
|
6307
6618
|
const { client, auth } = context;
|
|
@@ -6433,6 +6744,7 @@ function createAgent(options) {
|
|
|
6433
6744
|
legreffier: createLegreffierNamespace(context),
|
|
6434
6745
|
problems: createProblemsNamespace(context),
|
|
6435
6746
|
teams: createTeamsNamespace(context),
|
|
6747
|
+
tasks: createTasksNamespace(context),
|
|
6436
6748
|
client,
|
|
6437
6749
|
getToken: () => tokenManager.getToken()
|
|
6438
6750
|
};
|
|
@@ -6758,21 +7070,6 @@ var registerSandboxCommand = (pi, state) => {
|
|
|
6758
7070
|
};
|
|
6759
7071
|
//#endregion
|
|
6760
7072
|
//#region src/moltnet/judge/assets.ts
|
|
6761
|
-
/**
|
|
6762
|
-
* Judge assets — single source of truth.
|
|
6763
|
-
*
|
|
6764
|
-
* `DEFAULT_RUBRIC` and `JUDGE_SYSTEM_PROMPT` below ARE the assets. There are
|
|
6765
|
-
* no companion `.md` files; tsc does not copy non-TS files into `dist/`, and
|
|
6766
|
-
* keeping a parallel markdown copy invited drift between source-of-truth
|
|
6767
|
-
* versions, which is what previously happened.
|
|
6768
|
-
*
|
|
6769
|
-
* The asset path constants are opaque identifiers used in the judge-recipe
|
|
6770
|
-
* CID manifest so verifiers can trace which asset set a given Pi extension
|
|
6771
|
-
* version emitted. They are NOT filesystem paths and are never read.
|
|
6772
|
-
* Bump the version suffix when you change the corresponding constant.
|
|
6773
|
-
*/
|
|
6774
|
-
var RUBRIC_ASSET_PATH = "pi-extension/judge/rubric@v1";
|
|
6775
|
-
var JUDGE_PROMPT_ASSET_PATH = "pi-extension/judge/system-prompt@v1";
|
|
6776
7073
|
/** Default fidelity rubric — kept verbatim from the Go judge. */
|
|
6777
7074
|
var DEFAULT_RUBRIC = `Evaluate the rendered content against the source entries on three axes:
|
|
6778
7075
|
|
|
@@ -6925,135 +7222,6 @@ function buildSourceEntriesMarkdown(entries) {
|
|
|
6925
7222
|
return parts.join("\n");
|
|
6926
7223
|
}
|
|
6927
7224
|
//#endregion
|
|
6928
|
-
//#region src/moltnet/judge-recipe-cid.ts
|
|
6929
|
-
var require = createRequire(import.meta.url);
|
|
6930
|
-
var SELF_PACKAGE_NAME = "@themoltnet/pi-extension";
|
|
6931
|
-
var PI_PACKAGE_NAME = "@mariozechner/pi-coding-agent";
|
|
6932
|
-
var SDK_PACKAGE_NAME = "@themoltnet/sdk";
|
|
6933
|
-
var CID_VERSION = 1;
|
|
6934
|
-
var RAW_CODEC = 85;
|
|
6935
|
-
var SHA2_256_CODE = 18;
|
|
6936
|
-
var BASE32_ALPHABET = "abcdefghijklmnopqrstuvwxyz234567";
|
|
6937
|
-
function findSelfPackageDir() {
|
|
6938
|
-
const start = path.dirname(fileURLToPath(import.meta.url));
|
|
6939
|
-
let dir = start;
|
|
6940
|
-
while (true) {
|
|
6941
|
-
const candidate = path.join(dir, "package.json");
|
|
6942
|
-
if (existsSync(candidate)) {
|
|
6943
|
-
if (JSON.parse(readFileSync(candidate, "utf8")).name === SELF_PACKAGE_NAME) return dir;
|
|
6944
|
-
}
|
|
6945
|
-
const parent = path.dirname(dir);
|
|
6946
|
-
if (parent === dir) return start;
|
|
6947
|
-
dir = parent;
|
|
6948
|
-
}
|
|
6949
|
-
}
|
|
6950
|
-
var PACKAGE_DIR = findSelfPackageDir();
|
|
6951
|
-
function sha256Hex(value) {
|
|
6952
|
-
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
6953
|
-
}
|
|
6954
|
-
function encodeVarint(value) {
|
|
6955
|
-
const bytes = [];
|
|
6956
|
-
let current = value >>> 0;
|
|
6957
|
-
while (current >= 128) {
|
|
6958
|
-
bytes.push(current & 127 | 128);
|
|
6959
|
-
current >>>= 7;
|
|
6960
|
-
}
|
|
6961
|
-
bytes.push(current);
|
|
6962
|
-
return bytes;
|
|
6963
|
-
}
|
|
6964
|
-
function base32Lower(bytes) {
|
|
6965
|
-
let bits = 0;
|
|
6966
|
-
let value = 0;
|
|
6967
|
-
let output = "";
|
|
6968
|
-
for (const byte of bytes) {
|
|
6969
|
-
value = value << 8 | byte;
|
|
6970
|
-
bits += 8;
|
|
6971
|
-
while (bits >= 5) {
|
|
6972
|
-
output += BASE32_ALPHABET[value >>> bits - 5 & 31];
|
|
6973
|
-
bits -= 5;
|
|
6974
|
-
}
|
|
6975
|
-
}
|
|
6976
|
-
if (bits > 0) output += BASE32_ALPHABET[value << 5 - bits & 31];
|
|
6977
|
-
return `b${output}`;
|
|
6978
|
-
}
|
|
6979
|
-
function stableStringify(value) {
|
|
6980
|
-
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
6981
|
-
if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
6982
|
-
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
6983
|
-
}
|
|
6984
|
-
function readPackageVersion(pkgPath, expectedName) {
|
|
6985
|
-
if (!existsSync(pkgPath)) return null;
|
|
6986
|
-
const parsed = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
6987
|
-
if (expectedName && parsed.name !== expectedName) return null;
|
|
6988
|
-
return typeof parsed.version === "string" ? parsed.version : null;
|
|
6989
|
-
}
|
|
6990
|
-
function resolveInstalledPackageVersion(packageName) {
|
|
6991
|
-
const candidates = [];
|
|
6992
|
-
try {
|
|
6993
|
-
candidates.push(path.dirname(require.resolve(packageName)));
|
|
6994
|
-
} catch {}
|
|
6995
|
-
let dir = PACKAGE_DIR;
|
|
6996
|
-
while (true) {
|
|
6997
|
-
candidates.push(path.join(dir, "node_modules", packageName));
|
|
6998
|
-
const parent = path.dirname(dir);
|
|
6999
|
-
if (parent === dir) break;
|
|
7000
|
-
dir = parent;
|
|
7001
|
-
}
|
|
7002
|
-
for (const start of candidates) {
|
|
7003
|
-
let current = start;
|
|
7004
|
-
while (true) {
|
|
7005
|
-
const version = readPackageVersion(path.join(current, "package.json"), packageName);
|
|
7006
|
-
if (version) return version;
|
|
7007
|
-
const parent = path.dirname(current);
|
|
7008
|
-
if (parent === current) break;
|
|
7009
|
-
current = parent;
|
|
7010
|
-
}
|
|
7011
|
-
}
|
|
7012
|
-
return null;
|
|
7013
|
-
}
|
|
7014
|
-
function resolvePiJudgeRecipeVersions() {
|
|
7015
|
-
return {
|
|
7016
|
-
pi: resolveInstalledPackageVersion(PI_PACKAGE_NAME),
|
|
7017
|
-
piExtension: readPackageVersion(path.join(PACKAGE_DIR, "package.json"), SELF_PACKAGE_NAME),
|
|
7018
|
-
sdk: resolveInstalledPackageVersion(SDK_PACKAGE_NAME)
|
|
7019
|
-
};
|
|
7020
|
-
}
|
|
7021
|
-
function buildPiJudgeRecipeManifest(inputs) {
|
|
7022
|
-
return {
|
|
7023
|
-
kind: "pi-judge-recipe/v1",
|
|
7024
|
-
versions: {
|
|
7025
|
-
...resolvePiJudgeRecipeVersions(),
|
|
7026
|
-
...inputs.overrides
|
|
7027
|
-
},
|
|
7028
|
-
assets: {
|
|
7029
|
-
promptAsset: inputs.promptAsset ?? null,
|
|
7030
|
-
rubricAsset: inputs.rubricAsset ?? null,
|
|
7031
|
-
skillSourcePath: inputs.skillSourcePath ?? null
|
|
7032
|
-
},
|
|
7033
|
-
hashes: {
|
|
7034
|
-
judgePromptSha256: sha256Hex(inputs.judgePrompt),
|
|
7035
|
-
rubricSha256: sha256Hex(inputs.rubric),
|
|
7036
|
-
skillFragmentSha256: inputs.skillFragment ? sha256Hex(inputs.skillFragment) : null,
|
|
7037
|
-
implementationSha256: inputs.implementationSource ? sha256Hex(inputs.implementationSource) : null
|
|
7038
|
-
}
|
|
7039
|
-
};
|
|
7040
|
-
}
|
|
7041
|
-
function computePiJudgeRecipeCid(inputs) {
|
|
7042
|
-
const manifest = buildPiJudgeRecipeManifest(inputs);
|
|
7043
|
-
const manifestBytes = Buffer.from(stableStringify(manifest), "utf8");
|
|
7044
|
-
const digestBytes = createHash("sha256").update(manifestBytes).digest();
|
|
7045
|
-
return {
|
|
7046
|
-
cid: base32Lower(Uint8Array.from([
|
|
7047
|
-
...encodeVarint(CID_VERSION),
|
|
7048
|
-
...encodeVarint(RAW_CODEC),
|
|
7049
|
-
...encodeVarint(SHA2_256_CODE),
|
|
7050
|
-
...encodeVarint(digestBytes.length),
|
|
7051
|
-
...digestBytes
|
|
7052
|
-
])),
|
|
7053
|
-
manifest
|
|
7054
|
-
};
|
|
7055
|
-
}
|
|
7056
|
-
//#endregion
|
|
7057
7225
|
//#region src/moltnet/render-phase6.ts
|
|
7058
7226
|
function slugToTitle(value) {
|
|
7059
7227
|
return value.split(/[:/_-]+/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -7171,316 +7339,582 @@ function renderPhase6Markdown(pack) {
|
|
|
7171
7339
|
* These tools run on the host (not in the VM) via the MoltNet SDK,
|
|
7172
7340
|
* so agent credentials never touch the VM filesystem.
|
|
7173
7341
|
*/
|
|
7342
|
+
/**
|
|
7343
|
+
* Baseline env keys forwarded to host-exec child processes.
|
|
7344
|
+
* Callers can extend this set at sandbox startup via `MoltNetToolsConfig.hostExecBaseEnv`.
|
|
7345
|
+
*/
|
|
7346
|
+
var HOST_EXEC_DEFAULT_BASE_ENV = new Set([
|
|
7347
|
+
"PATH",
|
|
7348
|
+
"HOME",
|
|
7349
|
+
"LANG",
|
|
7350
|
+
"LC_ALL",
|
|
7351
|
+
"TMPDIR",
|
|
7352
|
+
"GIT_CONFIG_GLOBAL",
|
|
7353
|
+
"MOLTNET_CREDENTIALS_PATH",
|
|
7354
|
+
"GIT_AUTHOR_NAME",
|
|
7355
|
+
"GIT_AUTHOR_EMAIL",
|
|
7356
|
+
"GIT_COMMITTER_NAME",
|
|
7357
|
+
"GIT_COMMITTER_EMAIL",
|
|
7358
|
+
"SSH_AUTH_SOCK"
|
|
7359
|
+
]);
|
|
7174
7360
|
function ensureConnected(config) {
|
|
7175
7361
|
const agent = config.getAgent();
|
|
7176
7362
|
const diaryId = config.getDiaryId();
|
|
7177
7363
|
if (!agent || !diaryId) throw new Error("MoltNet not connected");
|
|
7178
7364
|
return {
|
|
7179
7365
|
agent,
|
|
7180
|
-
diaryId
|
|
7366
|
+
diaryId,
|
|
7367
|
+
teamId: config.getTeamId() ?? ""
|
|
7181
7368
|
};
|
|
7182
7369
|
}
|
|
7183
7370
|
/**
|
|
7184
7371
|
* Create all MoltNet tool definitions, ready to pass to `pi.registerTool()`.
|
|
7185
7372
|
*/
|
|
7186
7373
|
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
|
-
}
|
|
7374
|
+
const getPack = defineTool({
|
|
7375
|
+
name: "moltnet_pack_get",
|
|
7376
|
+
label: "Get MoltNet Pack",
|
|
7377
|
+
description: "Get a context pack by ID. Optionally expand included entries.",
|
|
7378
|
+
parameters: Type.Object({
|
|
7379
|
+
packId: Type.String({ description: "Context pack ID" }),
|
|
7380
|
+
expandEntries: Type.Optional(Type.Boolean({ description: "Include full expanded entries" }))
|
|
7207
7381
|
}),
|
|
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
|
-
}
|
|
7382
|
+
async execute(_id, params) {
|
|
7383
|
+
const { agent } = ensureConnected(config);
|
|
7384
|
+
const pack = await agent.packs.get(params.packId, { expand: params.expandEntries ? "entries" : void 0 });
|
|
7385
|
+
return {
|
|
7386
|
+
content: [{
|
|
7387
|
+
type: "text",
|
|
7388
|
+
text: JSON.stringify(pack, null, 2)
|
|
7389
|
+
}],
|
|
7390
|
+
details: {}
|
|
7391
|
+
};
|
|
7392
|
+
}
|
|
7393
|
+
});
|
|
7394
|
+
const createPack = defineTool({
|
|
7395
|
+
name: "moltnet_pack_create",
|
|
7396
|
+
label: "Create MoltNet Pack",
|
|
7397
|
+
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.",
|
|
7398
|
+
parameters: Type.Object({
|
|
7399
|
+
entries: Type.Array(Type.Object({
|
|
7400
|
+
entryId: Type.String({ description: "Diary entry UUID" }),
|
|
7401
|
+
rank: Type.Number({ description: "Rank (1..N, lower = more prominent)" })
|
|
7402
|
+
}), { description: "Selected entries with their ranks" }),
|
|
7403
|
+
params: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Free-form recipe parameters (recipe name, prompt, selection rationale, etc.)" })),
|
|
7404
|
+
tokenBudget: Type.Optional(Type.Number({ description: "Soft token budget recorded on the pack (optional)" })),
|
|
7405
|
+
pinned: Type.Optional(Type.Boolean({ description: "Pin the pack against retention policy (default false)" }))
|
|
7238
7406
|
}),
|
|
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
|
-
}
|
|
7407
|
+
async execute(_id, params) {
|
|
7408
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7409
|
+
const pack = await agent.packs.create(diaryId, {
|
|
7410
|
+
packType: "custom",
|
|
7411
|
+
params: params.params ?? {},
|
|
7412
|
+
entries: params.entries,
|
|
7413
|
+
tokenBudget: params.tokenBudget,
|
|
7414
|
+
pinned: params.pinned ?? false
|
|
7415
|
+
});
|
|
7416
|
+
return {
|
|
7417
|
+
content: [{
|
|
7418
|
+
type: "text",
|
|
7419
|
+
text: JSON.stringify(pack, null, 2)
|
|
7420
|
+
}],
|
|
7421
|
+
details: {}
|
|
7422
|
+
};
|
|
7423
|
+
}
|
|
7424
|
+
});
|
|
7425
|
+
const getPackProvenance = defineTool({
|
|
7426
|
+
name: "moltnet_pack_provenance",
|
|
7427
|
+
label: "Get MoltNet Pack Provenance",
|
|
7428
|
+
description: "Get the provenance graph for a context pack by ID or CID.",
|
|
7429
|
+
parameters: Type.Object({
|
|
7430
|
+
packId: Type.Optional(Type.String({ description: "Context pack ID" })),
|
|
7431
|
+
packCid: Type.Optional(Type.String({ description: "Context pack CID" })),
|
|
7432
|
+
depth: Type.Optional(Type.Number({ description: "Supersession ancestry depth to include (default 2)" }))
|
|
7269
7433
|
}),
|
|
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
|
-
}
|
|
7434
|
+
async execute(_id, params) {
|
|
7435
|
+
const { agent } = ensureConnected(config);
|
|
7436
|
+
if (!params.packId && !params.packCid) throw new Error("Provide either packId or packCid");
|
|
7437
|
+
if (params.packId && params.packCid) throw new Error("Provide only one of packId or packCid");
|
|
7438
|
+
const graph = params.packId ? await agent.packs.getProvenance(params.packId, { depth: params.depth ?? 2 }) : await agent.packs.getProvenanceByCid(params.packCid, { depth: params.depth ?? 2 });
|
|
7439
|
+
const payload = {
|
|
7440
|
+
metadata: graph.metadata,
|
|
7441
|
+
counts: {
|
|
7442
|
+
nodes: graph.nodes.length,
|
|
7443
|
+
edges: graph.edges.length
|
|
7444
|
+
},
|
|
7445
|
+
graph
|
|
7446
|
+
};
|
|
7447
|
+
return {
|
|
7448
|
+
content: [{
|
|
7449
|
+
type: "text",
|
|
7450
|
+
text: JSON.stringify(payload, null, 2)
|
|
7451
|
+
}],
|
|
7452
|
+
details: {}
|
|
7453
|
+
};
|
|
7454
|
+
}
|
|
7455
|
+
});
|
|
7456
|
+
const renderPack = defineTool({
|
|
7457
|
+
name: "moltnet_pack_render",
|
|
7458
|
+
label: "Render MoltNet Pack",
|
|
7459
|
+
description: "Fetch a pack with entries, transform it into docs, then preview or persist the rendered pack.",
|
|
7460
|
+
parameters: Type.Object({
|
|
7461
|
+
packId: Type.String({ description: "Context pack ID" }),
|
|
7462
|
+
renderMethod: Type.Optional(Type.String({ description: "Render method label. Defaults to pi:pack-to-docs-v1" })),
|
|
7463
|
+
markdown: Type.Optional(Type.String({ description: "Optional caller-authored markdown override" })),
|
|
7464
|
+
preview: Type.Optional(Type.Boolean({ description: "Preview without persisting (default false)" })),
|
|
7465
|
+
pinned: Type.Optional(Type.Boolean({ description: "Persist the rendered pack as pinned (default false)" }))
|
|
7302
7466
|
}),
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
renderMethod
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7467
|
+
async execute(_id, params) {
|
|
7468
|
+
const { agent } = ensureConnected(config);
|
|
7469
|
+
const renderMethod = params.renderMethod ?? "pi:pack-to-docs-v1";
|
|
7470
|
+
let renderedMarkdown = params.markdown;
|
|
7471
|
+
if (!renderedMarkdown && !renderMethod.startsWith("server:")) renderedMarkdown = renderPhase6Markdown(await agent.packs.get(params.packId, { expand: "entries" }));
|
|
7472
|
+
const result = params.preview ?? false ? await agent.packs.previewRendered(params.packId, {
|
|
7473
|
+
renderMethod,
|
|
7474
|
+
renderedMarkdown
|
|
7475
|
+
}) : await agent.packs.render(params.packId, {
|
|
7476
|
+
renderMethod,
|
|
7477
|
+
renderedMarkdown,
|
|
7478
|
+
pinned: params.pinned
|
|
7479
|
+
});
|
|
7480
|
+
return {
|
|
7481
|
+
content: [{
|
|
7482
|
+
type: "text",
|
|
7483
|
+
text: JSON.stringify(result, null, 2)
|
|
7484
|
+
}],
|
|
7485
|
+
details: {}
|
|
7486
|
+
};
|
|
7487
|
+
}
|
|
7488
|
+
});
|
|
7489
|
+
const listRenderedPacks = defineTool({
|
|
7490
|
+
name: "moltnet_rendered_pack_list",
|
|
7491
|
+
label: "List MoltNet Rendered Packs",
|
|
7492
|
+
description: "List rendered packs for the current MoltNet diary, optionally filtered by source pack or render method.",
|
|
7493
|
+
parameters: Type.Object({
|
|
7494
|
+
sourcePackId: Type.Optional(Type.String({ description: "Filter by source pack ID" })),
|
|
7495
|
+
renderMethod: Type.Optional(Type.String({ description: "Filter by render method" })),
|
|
7496
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 10)" })),
|
|
7497
|
+
offset: Type.Optional(Type.Number({ description: "Offset for pagination (default 0)" }))
|
|
7498
|
+
}),
|
|
7499
|
+
async execute(_id, params) {
|
|
7500
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7501
|
+
const rendered = await agent.packs.listRendered(diaryId, {
|
|
7502
|
+
sourcePackId: params.sourcePackId,
|
|
7503
|
+
renderMethod: params.renderMethod,
|
|
7504
|
+
limit: params.limit ?? 10,
|
|
7505
|
+
offset: params.offset ?? 0
|
|
7506
|
+
});
|
|
7507
|
+
return {
|
|
7508
|
+
content: [{
|
|
7509
|
+
type: "text",
|
|
7510
|
+
text: JSON.stringify(rendered, null, 2)
|
|
7511
|
+
}],
|
|
7512
|
+
details: {}
|
|
7513
|
+
};
|
|
7514
|
+
}
|
|
7515
|
+
});
|
|
7516
|
+
const getRenderedPack = defineTool({
|
|
7517
|
+
name: "moltnet_rendered_pack_get",
|
|
7518
|
+
label: "Get MoltNet Rendered Pack",
|
|
7519
|
+
description: "Get a rendered pack by ID.",
|
|
7520
|
+
parameters: Type.Object({ renderedPackId: Type.String({ description: "Rendered pack ID" }) }),
|
|
7521
|
+
async execute(_id, params) {
|
|
7522
|
+
const { agent } = ensureConnected(config);
|
|
7523
|
+
const rendered = await agent.packs.getRendered(params.renderedPackId);
|
|
7524
|
+
return {
|
|
7525
|
+
content: [{
|
|
7526
|
+
type: "text",
|
|
7527
|
+
text: JSON.stringify(rendered, null, 2)
|
|
7528
|
+
}],
|
|
7529
|
+
details: {}
|
|
7530
|
+
};
|
|
7531
|
+
}
|
|
7532
|
+
});
|
|
7533
|
+
const createJudgePackTask = defineTool({
|
|
7534
|
+
name: "moltnet_judge_pack_task_create",
|
|
7535
|
+
label: "Create Judge Pack Task",
|
|
7536
|
+
description: "Create a judge_pack task for a rendered pack. Returns a taskId that moltnet_rendered_pack_judge can claim and execute. The rubric is required — pass the structured rubric JSON from @moltnet/tasks Rubric schema.",
|
|
7537
|
+
parameters: Type.Object({
|
|
7538
|
+
renderedPackId: Type.String({ description: "Rendered pack ID to judge" }),
|
|
7539
|
+
sourcePackId: Type.String({ description: "Source pack ID. Fetch it from the rendered pack if unknown." }),
|
|
7540
|
+
rubric: Type.Any({ description: "Structured rubric object (Rubric schema from @moltnet/tasks). Must have rubricId, version, criteria[]." }),
|
|
7541
|
+
diaryId: Type.Optional(Type.String({ description: "Diary ID to impose the task on. Defaults to the connected diary." }))
|
|
7542
|
+
}),
|
|
7543
|
+
async execute(_id, params) {
|
|
7544
|
+
const { agent, diaryId: connectedDiaryId, teamId: connectedTeamId } = ensureConnected(config);
|
|
7545
|
+
const task = await agent.tasks.create({
|
|
7546
|
+
taskType: "judge_pack",
|
|
7547
|
+
input: {
|
|
7548
|
+
renderedPackId: params.renderedPackId,
|
|
7316
7549
|
sourcePackId: params.sourcePackId,
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7550
|
+
rubric: params.rubric
|
|
7551
|
+
},
|
|
7552
|
+
diaryId: params.diaryId ?? connectedDiaryId,
|
|
7553
|
+
teamId: connectedTeamId
|
|
7554
|
+
});
|
|
7555
|
+
return {
|
|
7556
|
+
content: [{
|
|
7557
|
+
type: "text",
|
|
7558
|
+
text: JSON.stringify({
|
|
7559
|
+
taskId: task.id,
|
|
7560
|
+
task
|
|
7561
|
+
}, null, 2)
|
|
7562
|
+
}],
|
|
7563
|
+
details: {}
|
|
7564
|
+
};
|
|
7565
|
+
}
|
|
7566
|
+
});
|
|
7567
|
+
const judgeRenderedPack = defineTool({
|
|
7568
|
+
name: "moltnet_rendered_pack_judge",
|
|
7569
|
+
label: "Judge MoltNet Rendered Pack",
|
|
7570
|
+
description: "Claim a judge_pack task, run the fidelity judge locally, complete the task with structured scores, and set verifiedTaskId on the rendered pack. Create the task first with moltnet_judge_pack_task_create.",
|
|
7571
|
+
parameters: Type.Object({
|
|
7572
|
+
taskId: Type.String({ description: "judge_pack task ID from moltnet_judge_pack_task_create" }),
|
|
7573
|
+
rubricOverride: Type.Optional(Type.String({ description: "Freeform rubric string override for the LLM judge prompt. When omitted the task rubric preamble (or built-in default) is used." }))
|
|
7574
|
+
}),
|
|
7575
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
7576
|
+
const { agent } = ensureConnected(config);
|
|
7577
|
+
const model = ctx?.model;
|
|
7578
|
+
if (!model) throw new Error("No active model in pi session — cannot run the fidelity judge.");
|
|
7579
|
+
const claimed = await agent.tasks.claim(params.taskId);
|
|
7580
|
+
const input = claimed.task.input;
|
|
7581
|
+
const rendered = await agent.packs.getRendered(input.renderedPackId);
|
|
7582
|
+
if (!rendered.content?.trim()) throw new Error(`rendered pack ${input.renderedPackId} has empty content`);
|
|
7583
|
+
const sourcePack = await agent.packs.get(input.sourcePackId, { expand: "entries" });
|
|
7584
|
+
if (!sourcePack.entries || sourcePack.entries.length === 0) throw new Error(`source pack ${input.sourcePackId} has no entries`);
|
|
7585
|
+
const sourceEntriesMd = buildSourceEntriesMarkdown(sourcePack.entries.map((entry) => ({
|
|
7586
|
+
title: entry.entry.title,
|
|
7587
|
+
content: entry.entry.content
|
|
7588
|
+
})));
|
|
7589
|
+
const rubric = params.rubricOverride?.trim() || input.rubric?.preamble?.trim() || DEFAULT_RUBRIC;
|
|
7590
|
+
let scores;
|
|
7591
|
+
try {
|
|
7592
|
+
scores = await runFidelityJudge({
|
|
7593
|
+
model,
|
|
7594
|
+
sourceEntries: sourceEntriesMd,
|
|
7595
|
+
renderedContent: rendered.content,
|
|
7596
|
+
rubric
|
|
7320
7597
|
});
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
};
|
|
7598
|
+
} catch (err) {
|
|
7599
|
+
await agent.tasks.fail(params.taskId, claimed.attempt.attemptN, { error: {
|
|
7600
|
+
code: "judge_failed",
|
|
7601
|
+
message: err.message ?? String(err)
|
|
7602
|
+
} }).catch(() => {});
|
|
7603
|
+
throw new Error(`judge failed: ${err.message ?? String(err)}`);
|
|
7328
7604
|
}
|
|
7605
|
+
const modelId = model.provider && model.id ? `${model.provider}:${model.id}` : model.id ?? "pi:unknown";
|
|
7606
|
+
const output = {
|
|
7607
|
+
scores: [
|
|
7608
|
+
{
|
|
7609
|
+
criterionId: "coverage",
|
|
7610
|
+
score: scores.coverage
|
|
7611
|
+
},
|
|
7612
|
+
{
|
|
7613
|
+
criterionId: "grounding",
|
|
7614
|
+
score: scores.grounding
|
|
7615
|
+
},
|
|
7616
|
+
{
|
|
7617
|
+
criterionId: "faithfulness",
|
|
7618
|
+
score: scores.faithfulness
|
|
7619
|
+
}
|
|
7620
|
+
],
|
|
7621
|
+
composite: scores.composite,
|
|
7622
|
+
verdict: scores.reasoning,
|
|
7623
|
+
judgeModel: modelId
|
|
7624
|
+
};
|
|
7625
|
+
const outputCid = await computeJsonCid(output);
|
|
7626
|
+
const completed = await agent.tasks.complete(params.taskId, claimed.attempt.attemptN, {
|
|
7627
|
+
output,
|
|
7628
|
+
outputCid,
|
|
7629
|
+
usage: {
|
|
7630
|
+
inputTokens: 0,
|
|
7631
|
+
outputTokens: 0
|
|
7632
|
+
}
|
|
7633
|
+
});
|
|
7634
|
+
await agent.packs.updateRendered(input.renderedPackId, { verifiedTaskId: params.taskId });
|
|
7635
|
+
return {
|
|
7636
|
+
content: [{
|
|
7637
|
+
type: "text",
|
|
7638
|
+
text: JSON.stringify({
|
|
7639
|
+
renderedPackId: input.renderedPackId,
|
|
7640
|
+
taskId: params.taskId,
|
|
7641
|
+
scores,
|
|
7642
|
+
task: completed
|
|
7643
|
+
}, null, 2)
|
|
7644
|
+
}],
|
|
7645
|
+
details: {}
|
|
7646
|
+
};
|
|
7647
|
+
}
|
|
7648
|
+
});
|
|
7649
|
+
const diaryTags = defineTool({
|
|
7650
|
+
name: "moltnet_diary_tags",
|
|
7651
|
+
label: "List MoltNet Diary Tags",
|
|
7652
|
+
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.",
|
|
7653
|
+
parameters: Type.Object({
|
|
7654
|
+
prefix: Type.Optional(Type.String({ description: "Filter to tags starting with this prefix (e.g. \"scope:\")" })),
|
|
7655
|
+
minCount: Type.Optional(Type.Number({ description: "Exclude tags with fewer than this many entries" })),
|
|
7656
|
+
entryTypes: Type.Optional(Type.Array(Type.Union([
|
|
7657
|
+
Type.Literal("episodic"),
|
|
7658
|
+
Type.Literal("semantic"),
|
|
7659
|
+
Type.Literal("procedural"),
|
|
7660
|
+
Type.Literal("reflection"),
|
|
7661
|
+
Type.Literal("identity"),
|
|
7662
|
+
Type.Literal("soul")
|
|
7663
|
+
]), { description: "Scope the tag count to these entry types" }))
|
|
7329
7664
|
}),
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7665
|
+
async execute(_id, params) {
|
|
7666
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7667
|
+
const result = await agent.diaries.tags(diaryId, {
|
|
7668
|
+
prefix: params.prefix,
|
|
7669
|
+
minCount: params.minCount,
|
|
7670
|
+
entryTypes: params.entryTypes
|
|
7671
|
+
});
|
|
7672
|
+
return {
|
|
7673
|
+
content: [{
|
|
7674
|
+
type: "text",
|
|
7675
|
+
text: JSON.stringify(result, null, 2)
|
|
7676
|
+
}],
|
|
7677
|
+
details: {}
|
|
7678
|
+
};
|
|
7679
|
+
}
|
|
7680
|
+
});
|
|
7681
|
+
const listEntries = defineTool({
|
|
7682
|
+
name: "moltnet_list_entries",
|
|
7683
|
+
label: "List MoltNet Diary Entries",
|
|
7684
|
+
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.",
|
|
7685
|
+
parameters: Type.Object({
|
|
7686
|
+
limit: Type.Optional(Type.Number({ description: "Max entries to return (default 10)" })),
|
|
7687
|
+
tag: Type.Optional(Type.String({ description: "Filter by tag (optional)" })),
|
|
7688
|
+
entryIds: Type.Optional(Type.Array(Type.String(), {
|
|
7689
|
+
description: "Batch-fetch specific entries by UUID (max 50). Overrides `limit` and `tag` for selection.",
|
|
7690
|
+
maxItems: 50
|
|
7691
|
+
}))
|
|
7346
7692
|
}),
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
const verification = await agent.packs.verifyRendered(params.renderedPackId, { nonce });
|
|
7359
|
-
return {
|
|
7360
|
-
content: [{
|
|
7361
|
-
type: "text",
|
|
7362
|
-
text: JSON.stringify({
|
|
7363
|
-
...verification,
|
|
7364
|
-
nonce
|
|
7365
|
-
}, null, 2)
|
|
7366
|
-
}],
|
|
7367
|
-
details: {}
|
|
7368
|
-
};
|
|
7693
|
+
async execute(_id, params) {
|
|
7694
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7695
|
+
const query = {
|
|
7696
|
+
orderBy: "createdAt",
|
|
7697
|
+
order: "desc"
|
|
7698
|
+
};
|
|
7699
|
+
const batchMode = !!params.entryIds?.length;
|
|
7700
|
+
if (batchMode) query.ids = params.entryIds;
|
|
7701
|
+
else {
|
|
7702
|
+
query.limit = params.limit ?? 10;
|
|
7703
|
+
if (params.tag) query.tag = params.tag;
|
|
7369
7704
|
}
|
|
7705
|
+
const entries = await agent.entries.list(diaryId, query);
|
|
7706
|
+
return {
|
|
7707
|
+
content: [{
|
|
7708
|
+
type: "text",
|
|
7709
|
+
text: JSON.stringify(entries.items?.map((e) => batchMode ? {
|
|
7710
|
+
id: e.id,
|
|
7711
|
+
title: e.title,
|
|
7712
|
+
entryType: e.entryType,
|
|
7713
|
+
tags: e.tags,
|
|
7714
|
+
importance: e.importance,
|
|
7715
|
+
contentHash: e.contentHash,
|
|
7716
|
+
contentSignature: e.contentSignature,
|
|
7717
|
+
signingNonce: e.signingNonce,
|
|
7718
|
+
createdAt: e.createdAt
|
|
7719
|
+
} : {
|
|
7720
|
+
id: e.id,
|
|
7721
|
+
title: e.title,
|
|
7722
|
+
tags: e.tags,
|
|
7723
|
+
importance: e.importance,
|
|
7724
|
+
createdAt: e.createdAt,
|
|
7725
|
+
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
7726
|
+
}), null, 2)
|
|
7727
|
+
}],
|
|
7728
|
+
details: {}
|
|
7729
|
+
};
|
|
7730
|
+
}
|
|
7731
|
+
});
|
|
7732
|
+
const getEntry = defineTool({
|
|
7733
|
+
name: "moltnet_get_entry",
|
|
7734
|
+
label: "Get MoltNet Diary Entry",
|
|
7735
|
+
description: "Get the full content of a specific diary entry by ID.",
|
|
7736
|
+
parameters: Type.Object({ entryId: Type.String({ description: "The entry ID to fetch" }) }),
|
|
7737
|
+
async execute(_id, params) {
|
|
7738
|
+
const { agent } = ensureConnected(config);
|
|
7739
|
+
const entry = await agent.entries.get(params.entryId);
|
|
7740
|
+
return {
|
|
7741
|
+
content: [{
|
|
7742
|
+
type: "text",
|
|
7743
|
+
text: JSON.stringify({
|
|
7744
|
+
id: entry.id,
|
|
7745
|
+
title: entry.title,
|
|
7746
|
+
content: entry.content,
|
|
7747
|
+
tags: entry.tags,
|
|
7748
|
+
importance: entry.importance,
|
|
7749
|
+
createdAt: entry.createdAt
|
|
7750
|
+
}, null, 2)
|
|
7751
|
+
}],
|
|
7752
|
+
details: {}
|
|
7753
|
+
};
|
|
7754
|
+
}
|
|
7755
|
+
});
|
|
7756
|
+
const searchEntries = defineTool({
|
|
7757
|
+
name: "moltnet_search_entries",
|
|
7758
|
+
label: "Search MoltNet Diary Entries",
|
|
7759
|
+
description: "Search diary entries by semantic query. Uses vector similarity to find relevant entries.",
|
|
7760
|
+
parameters: Type.Object({
|
|
7761
|
+
query: Type.String({ description: "Natural language search query" }),
|
|
7762
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 5)" }))
|
|
7763
|
+
}),
|
|
7764
|
+
async execute(_id, params) {
|
|
7765
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7766
|
+
const results = await agent.entries.search({
|
|
7767
|
+
diaryId,
|
|
7768
|
+
query: params.query,
|
|
7769
|
+
limit: params.limit ?? 5
|
|
7770
|
+
});
|
|
7771
|
+
return {
|
|
7772
|
+
content: [{
|
|
7773
|
+
type: "text",
|
|
7774
|
+
text: JSON.stringify(results.results?.map((e) => ({
|
|
7775
|
+
id: e.id,
|
|
7776
|
+
title: e.title,
|
|
7777
|
+
tags: e.tags,
|
|
7778
|
+
importance: e.importance,
|
|
7779
|
+
contentPreview: typeof e.content === "string" ? e.content.slice(0, 200) : void 0
|
|
7780
|
+
})), null, 2)
|
|
7781
|
+
}],
|
|
7782
|
+
details: {}
|
|
7783
|
+
};
|
|
7784
|
+
}
|
|
7785
|
+
});
|
|
7786
|
+
const createEntry = defineTool({
|
|
7787
|
+
name: "moltnet_create_entry",
|
|
7788
|
+
label: "Create MoltNet Diary Entry",
|
|
7789
|
+
description: "Create a new diary entry to record decisions, findings, incidents, or reflections.",
|
|
7790
|
+
parameters: Type.Object({
|
|
7791
|
+
title: Type.String({ description: "Entry title (concise, descriptive)" }),
|
|
7792
|
+
content: Type.String({ description: "Entry content (markdown)" }),
|
|
7793
|
+
tags: Type.Optional(Type.Array(Type.String(), { description: "Tags for categorization" })),
|
|
7794
|
+
importance: Type.Optional(Type.Number({ description: "Importance 1-10 (default 5)" }))
|
|
7370
7795
|
}),
|
|
7796
|
+
async execute(_id, params) {
|
|
7797
|
+
const { agent, diaryId } = ensureConnected(config);
|
|
7798
|
+
const entry = await agent.entries.create(diaryId, {
|
|
7799
|
+
title: params.title,
|
|
7800
|
+
content: params.content,
|
|
7801
|
+
tags: params.tags ?? [],
|
|
7802
|
+
importance: params.importance ?? 5
|
|
7803
|
+
});
|
|
7804
|
+
return {
|
|
7805
|
+
content: [{
|
|
7806
|
+
type: "text",
|
|
7807
|
+
text: JSON.stringify({
|
|
7808
|
+
id: entry.id,
|
|
7809
|
+
title: entry.title,
|
|
7810
|
+
createdAt: entry.createdAt
|
|
7811
|
+
}, null, 2)
|
|
7812
|
+
}],
|
|
7813
|
+
details: {}
|
|
7814
|
+
};
|
|
7815
|
+
}
|
|
7816
|
+
});
|
|
7817
|
+
const reviewSessionErrors = defineTool({
|
|
7818
|
+
name: "moltnet_review_session_errors",
|
|
7819
|
+
label: "Review Session Tool Errors",
|
|
7820
|
+
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.",
|
|
7821
|
+
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." })) }),
|
|
7822
|
+
async execute(_id, params) {
|
|
7823
|
+
const errors = config.getSessionErrors();
|
|
7824
|
+
const payload = {
|
|
7825
|
+
count: errors.length,
|
|
7826
|
+
errors: errors.map((e) => ({
|
|
7827
|
+
toolName: e.toolName,
|
|
7828
|
+
toolCallId: e.toolCallId,
|
|
7829
|
+
timestamp: new Date(e.timestamp).toISOString(),
|
|
7830
|
+
input: e.input,
|
|
7831
|
+
error: e.error
|
|
7832
|
+
}))
|
|
7833
|
+
};
|
|
7834
|
+
if (params.clear) config.clearSessionErrors();
|
|
7835
|
+
return {
|
|
7836
|
+
content: [{
|
|
7837
|
+
type: "text",
|
|
7838
|
+
text: JSON.stringify(payload, null, 2)
|
|
7839
|
+
}],
|
|
7840
|
+
details: {}
|
|
7841
|
+
};
|
|
7842
|
+
}
|
|
7843
|
+
});
|
|
7844
|
+
const HOST_EXEC_ALLOWED = new Set([
|
|
7845
|
+
"git",
|
|
7846
|
+
"gh",
|
|
7847
|
+
"moltnet"
|
|
7848
|
+
]);
|
|
7849
|
+
const hostExecBaseEnv = config.hostExecBaseEnv ?? HOST_EXEC_DEFAULT_BASE_ENV;
|
|
7850
|
+
const HOST_EXEC_TIMEOUT_MS = 6e4;
|
|
7851
|
+
return [
|
|
7852
|
+
getPack,
|
|
7853
|
+
createPack,
|
|
7854
|
+
getPackProvenance,
|
|
7855
|
+
renderPack,
|
|
7856
|
+
listRenderedPacks,
|
|
7857
|
+
getRenderedPack,
|
|
7858
|
+
createJudgePackTask,
|
|
7859
|
+
judgeRenderedPack,
|
|
7860
|
+
diaryTags,
|
|
7861
|
+
listEntries,
|
|
7862
|
+
getEntry,
|
|
7863
|
+
searchEntries,
|
|
7864
|
+
createEntry,
|
|
7865
|
+
reviewSessionErrors,
|
|
7371
7866
|
defineTool({
|
|
7372
|
-
name: "
|
|
7373
|
-
label: "
|
|
7374
|
-
description: "
|
|
7867
|
+
name: "moltnet_host_exec",
|
|
7868
|
+
label: "Run command on host (escape hatch — requires user approval)",
|
|
7869
|
+
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
7870
|
parameters: Type.Object({
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7871
|
+
executable: Type.String({ description: "Executable to run (git | gh | moltnet)" }),
|
|
7872
|
+
args: Type.Array(Type.String(), { description: "Arguments to pass to the executable" }),
|
|
7873
|
+
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
7874
|
}),
|
|
7380
7875
|
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;
|
|
7876
|
+
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.`);
|
|
7877
|
+
if (ctx?.ui) {
|
|
7878
|
+
const cmdDisplay = [params.executable, ...params.args].join(" ");
|
|
7879
|
+
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}`);
|
|
7880
|
+
}
|
|
7881
|
+
const cwd = config.getHostCwd?.() ?? process.cwd();
|
|
7882
|
+
const baseEnv = {};
|
|
7883
|
+
for (const key of hostExecBaseEnv) {
|
|
7884
|
+
const val = process.env[key];
|
|
7885
|
+
if (val !== void 0) baseEnv[key] = val;
|
|
7404
7886
|
}
|
|
7405
|
-
|
|
7887
|
+
const mergedEnv = {
|
|
7888
|
+
...baseEnv,
|
|
7889
|
+
...params.env ?? {}
|
|
7890
|
+
};
|
|
7891
|
+
let stdout;
|
|
7892
|
+
let stderr = "";
|
|
7406
7893
|
try {
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7894
|
+
stdout = execFileSync(params.executable, params.args, {
|
|
7895
|
+
encoding: "utf8",
|
|
7896
|
+
cwd,
|
|
7897
|
+
env: mergedEnv,
|
|
7898
|
+
stdio: [
|
|
7899
|
+
"pipe",
|
|
7900
|
+
"pipe",
|
|
7901
|
+
"pipe"
|
|
7902
|
+
],
|
|
7903
|
+
timeout: HOST_EXEC_TIMEOUT_MS
|
|
7412
7904
|
});
|
|
7413
7905
|
} catch (err) {
|
|
7414
|
-
|
|
7906
|
+
const e = err;
|
|
7907
|
+
stdout = e.stdout ?? "";
|
|
7908
|
+
stderr = e.stderr ?? e.message ?? String(err);
|
|
7415
7909
|
}
|
|
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: {}
|
|
7910
|
+
const result = {
|
|
7911
|
+
host_exec: true,
|
|
7912
|
+
executable: params.executable,
|
|
7913
|
+
args: params.args,
|
|
7914
|
+
cwd,
|
|
7915
|
+
stdout: stdout.trimEnd(),
|
|
7916
|
+
stderr: stderr.trimEnd() || void 0
|
|
7458
7917
|
};
|
|
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
7918
|
return {
|
|
7485
7919
|
content: [{
|
|
7486
7920
|
type: "text",
|
|
@@ -7489,169 +7923,6 @@ function createMoltNetTools(config) {
|
|
|
7489
7923
|
details: {}
|
|
7490
7924
|
};
|
|
7491
7925
|
}
|
|
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
7926
|
})
|
|
7656
7927
|
];
|
|
7657
7928
|
}
|
|
@@ -7987,10 +8258,6 @@ function createGondolinBashOps(vm, localCwd) {
|
|
|
7987
8258
|
}
|
|
7988
8259
|
//#endregion
|
|
7989
8260
|
//#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
8261
|
var GUEST_WORKSPACE$1 = "/workspace";
|
|
7995
8262
|
/**
|
|
7996
8263
|
* Resolve the main worktree root (where .moltnet/ lives — it's untracked,
|
|
@@ -8021,6 +8288,15 @@ function loadCredentials(agentDir) {
|
|
|
8021
8288
|
const sshPrivateKey = existsSync(path.join(sshDir, "id_ed25519")) ? readFileSync(path.join(sshDir, "id_ed25519"), "utf8") : null;
|
|
8022
8289
|
const sshPublicKey = existsSync(path.join(sshDir, "id_ed25519.pub")) ? readFileSync(path.join(sshDir, "id_ed25519.pub"), "utf8") : null;
|
|
8023
8290
|
const allowedSigners = existsSync(path.join(sshDir, "allowed_signers")) ? readFileSync(path.join(sshDir, "allowed_signers"), "utf8") : null;
|
|
8291
|
+
let githubAppPem = null;
|
|
8292
|
+
let githubAppPemFilename = null;
|
|
8293
|
+
const pemPath = JSON.parse(moltnetJson).github?.private_key_path;
|
|
8294
|
+
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
|
|
8295
|
+
`);
|
|
8296
|
+
else {
|
|
8297
|
+
githubAppPem = readFileSync(pemPath, "utf8");
|
|
8298
|
+
githubAppPemFilename = path.basename(pemPath);
|
|
8299
|
+
}
|
|
8024
8300
|
return {
|
|
8025
8301
|
moltnetJson,
|
|
8026
8302
|
agentEnvRaw,
|
|
@@ -8029,7 +8305,9 @@ function loadCredentials(agentDir) {
|
|
|
8029
8305
|
gitconfig,
|
|
8030
8306
|
sshPrivateKey,
|
|
8031
8307
|
sshPublicKey,
|
|
8032
|
-
allowedSigners
|
|
8308
|
+
allowedSigners,
|
|
8309
|
+
githubAppPem,
|
|
8310
|
+
githubAppPemFilename
|
|
8033
8311
|
};
|
|
8034
8312
|
}
|
|
8035
8313
|
/**
|
|
@@ -8076,81 +8354,250 @@ async function resumeVm(config) {
|
|
|
8076
8354
|
apiHost,
|
|
8077
8355
|
...config.extraAllowedHosts ?? []
|
|
8078
8356
|
] });
|
|
8357
|
+
const vmAgentDir = `/home/agent/.moltnet/${config.agentName}`;
|
|
8079
8358
|
const vmAgentEnv = {};
|
|
8080
8359
|
for (const [k, v] of Object.entries(creds.agentEnv)) {
|
|
8081
8360
|
if (v === void 0 || v === "") continue;
|
|
8082
|
-
if (k === "GIT_CONFIG_GLOBAL") vmAgentEnv[k] =
|
|
8083
|
-
else if (k.endsWith("_PRIVATE_KEY_PATH")) vmAgentEnv[k] =
|
|
8361
|
+
if (k === "GIT_CONFIG_GLOBAL") vmAgentEnv[k] = `${vmAgentDir}/gitconfig`;
|
|
8362
|
+
else if (k.endsWith("_PRIVATE_KEY_PATH")) vmAgentEnv[k] = `${vmAgentDir}/${path.basename(v)}`;
|
|
8084
8363
|
else vmAgentEnv[k] = v;
|
|
8085
8364
|
}
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8365
|
+
vmAgentEnv.MOLTNET_CREDENTIALS_PATH = `${vmAgentDir}/moltnet.json`;
|
|
8366
|
+
const vfsConfig = config.sandboxConfig?.vfs;
|
|
8367
|
+
let workspaceProvider = new RealFSProvider(config.mountPath);
|
|
8368
|
+
if (vfsConfig?.shadow?.length) {
|
|
8369
|
+
const predicate = createShadowPathPredicate(vfsConfig.shadow);
|
|
8370
|
+
workspaceProvider = new ShadowProvider(workspaceProvider, {
|
|
8371
|
+
shouldShadow: predicate,
|
|
8372
|
+
writeMode: vfsConfig.shadowMode ?? "tmpfs"
|
|
8373
|
+
});
|
|
8374
|
+
}
|
|
8375
|
+
const envOverrides = config.sandboxConfig?.env ?? {};
|
|
8376
|
+
const vmEnv = {
|
|
8377
|
+
...secretEnv,
|
|
8378
|
+
...vmAgentEnv,
|
|
8379
|
+
PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/go/bin",
|
|
8380
|
+
HOME: "/home/agent",
|
|
8381
|
+
NODE_NO_WARNINGS: "1",
|
|
8382
|
+
NODE_EXTRA_CA_CERTS: "/etc/ssl/certs/ca-certificates.crt",
|
|
8383
|
+
...envOverrides
|
|
8384
|
+
};
|
|
8385
|
+
const resources = config.sandboxConfig?.resources;
|
|
8386
|
+
const vm = await VmCheckpoint.load(config.checkpointPath).resume({
|
|
8387
|
+
httpHooks,
|
|
8388
|
+
env: vmEnv,
|
|
8389
|
+
...resources?.memory && { memory: resources.memory },
|
|
8390
|
+
...resources?.cpus && { cpus: resources.cpus },
|
|
8391
|
+
vfs: { mounts: { [GUEST_WORKSPACE$1]: workspaceProvider } }
|
|
8392
|
+
});
|
|
8393
|
+
await vm.exec(`sh -c '
|
|
8394
|
+
cp /etc/gondolin/mitm/ca.crt /usr/local/share/ca-certificates/gondolin-mitm.crt
|
|
8395
|
+
update-ca-certificates 2>/dev/null
|
|
8396
|
+
cat /etc/gondolin/mitm/ca.crt >> /etc/ssl/certs/ca-certificates.crt
|
|
8397
|
+
'`);
|
|
8398
|
+
await vm.exec(`sh -c 'echo "nameserver 8.8.8.8
|
|
8399
|
+
nameserver 1.1.1.1" > /etc/resolv.conf'`);
|
|
8400
|
+
const vmSshDir = `${vmAgentDir}/ssh`;
|
|
8401
|
+
await vm.exec(`mkdir -p ${vmAgentDir}/ssh /home/agent/.pi/agent`);
|
|
8402
|
+
await vm.fs.writeFile("/home/agent/.pi/agent/auth.json", creds.piAuthJson, { mode: 384 });
|
|
8403
|
+
const vmMoltnetJson = rewriteMoltnetJsonPaths(creds.moltnetJson, vmAgentDir, vmSshDir, creds.githubAppPemFilename);
|
|
8404
|
+
await vm.fs.writeFile(`${vmAgentDir}/moltnet.json`, vmMoltnetJson, { mode: 384 });
|
|
8405
|
+
await vm.fs.writeFile(`${vmAgentDir}/env`, creds.agentEnvRaw, { mode: 384 });
|
|
8406
|
+
if (creds.gitconfig) {
|
|
8407
|
+
const vmSigningKey = `${vmSshDir}/id_ed25519`;
|
|
8408
|
+
let vmGitconfig = creds.gitconfig.replace(/signingKey\s*=\s*.+/g, `signingKey = ${vmSigningKey}`);
|
|
8409
|
+
vmGitconfig = ensureRelativeWorktreePaths(vmGitconfig);
|
|
8410
|
+
await vm.fs.writeFile(`${vmAgentDir}/gitconfig`, vmGitconfig, { mode: 420 });
|
|
8411
|
+
}
|
|
8412
|
+
if (creds.sshPrivateKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519`, creds.sshPrivateKey, { mode: 384 });
|
|
8413
|
+
if (creds.sshPublicKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519.pub`, creds.sshPublicKey, { mode: 420 });
|
|
8414
|
+
if (creds.allowedSigners) await vm.fs.writeFile(`${vmSshDir}/allowed_signers`, creds.allowedSigners, { mode: 420 });
|
|
8415
|
+
if (creds.githubAppPem && creds.githubAppPemFilename) await vm.fs.writeFile(`${vmAgentDir}/${creds.githubAppPemFilename}`, creds.githubAppPem, { mode: 384 });
|
|
8416
|
+
await vm.exec("chown -R agent:agent /home/agent/.pi /home/agent/.moltnet");
|
|
8417
|
+
return {
|
|
8418
|
+
vm,
|
|
8419
|
+
credentials: creds,
|
|
8420
|
+
mountPath: config.mountPath,
|
|
8421
|
+
guestWorkspace: GUEST_WORKSPACE$1,
|
|
8422
|
+
agentDir
|
|
8423
|
+
};
|
|
8424
|
+
}
|
|
8425
|
+
/**
|
|
8426
|
+
* Rewrite host-absolute paths inside moltnet.json to VM-local equivalents.
|
|
8427
|
+
*
|
|
8428
|
+
* Fields rewritten:
|
|
8429
|
+
* ssh.private_key_path → <vmSshDir>/<basename of original>
|
|
8430
|
+
* ssh.public_key_path → <vmSshDir>/<basename of original>
|
|
8431
|
+
* git.config_path → <vmAgentDir>/gitconfig
|
|
8432
|
+
* github.private_key_path → <vmAgentDir>/<pemFilename> (if present)
|
|
8433
|
+
*
|
|
8434
|
+
* All other fields are passed through unchanged.
|
|
8435
|
+
* Throws if moltnetJson is not valid JSON — callers must not inject a broken
|
|
8436
|
+
* moltnet.json into the guest.
|
|
8437
|
+
*/
|
|
8438
|
+
function rewriteMoltnetJsonPaths(moltnetJson, vmAgentDir, vmSshDir, githubAppPemFilename) {
|
|
8439
|
+
const config = JSON.parse(moltnetJson);
|
|
8440
|
+
if (config.ssh && typeof config.ssh === "object") {
|
|
8441
|
+
const ssh = config.ssh;
|
|
8442
|
+
const origPrivate = typeof ssh.private_key_path === "string" ? ssh.private_key_path : null;
|
|
8443
|
+
const origPublic = typeof ssh.public_key_path === "string" ? ssh.public_key_path : null;
|
|
8444
|
+
config.ssh = {
|
|
8445
|
+
...ssh,
|
|
8446
|
+
...origPrivate !== null && { private_key_path: `${vmSshDir}/${path.basename(origPrivate)}` },
|
|
8447
|
+
...origPublic !== null && { public_key_path: `${vmSshDir}/${path.basename(origPublic)}` }
|
|
8448
|
+
};
|
|
8449
|
+
}
|
|
8450
|
+
if (config.git && typeof config.git === "object") {
|
|
8451
|
+
const git = { ...config.git };
|
|
8452
|
+
git.config_path = `${vmAgentDir}/gitconfig`;
|
|
8453
|
+
config.git = git;
|
|
8454
|
+
}
|
|
8455
|
+
if (githubAppPemFilename && config.github && typeof config.github === "object") {
|
|
8456
|
+
const github = { ...config.github };
|
|
8457
|
+
github.private_key_path = `${vmAgentDir}/${githubAppPemFilename}`;
|
|
8458
|
+
config.github = github;
|
|
8459
|
+
}
|
|
8460
|
+
return JSON.stringify(config);
|
|
8461
|
+
}
|
|
8462
|
+
/**
|
|
8463
|
+
* Ensure `[worktree] useRelativePaths = true` is set in the given
|
|
8464
|
+
* gitconfig text. If the section exists, rewrite the key; otherwise
|
|
8465
|
+
* append a new section.
|
|
8466
|
+
*/
|
|
8467
|
+
function ensureRelativeWorktreePaths(gitconfig) {
|
|
8468
|
+
const sectionRe = /^\[worktree\]\s*$/m;
|
|
8469
|
+
if (/^(\[worktree\][\s\S]*?^)\s*useRelativePaths\s*=\s*\S+\s*$/m.test(gitconfig)) return gitconfig.replace(/^(\s*useRelativePaths\s*=\s*)\S+\s*$/m, "$1true");
|
|
8470
|
+
if (sectionRe.test(gitconfig)) return gitconfig.replace(sectionRe, "[worktree]\n useRelativePaths = true");
|
|
8471
|
+
return `${gitconfig}${gitconfig.endsWith("\n") ? "" : "\n"}[worktree]\n\tuseRelativePaths = true\n`;
|
|
8472
|
+
}
|
|
8473
|
+
//#endregion
|
|
8474
|
+
//#region src/moltnet/judge-recipe-cid.ts
|
|
8475
|
+
var require = createRequire(import.meta.url);
|
|
8476
|
+
var SELF_PACKAGE_NAME = "@themoltnet/pi-extension";
|
|
8477
|
+
var PI_PACKAGE_NAME = "@mariozechner/pi-coding-agent";
|
|
8478
|
+
var SDK_PACKAGE_NAME = "@themoltnet/sdk";
|
|
8479
|
+
var CID_VERSION = 1;
|
|
8480
|
+
var RAW_CODEC = 85;
|
|
8481
|
+
var SHA2_256_CODE = 18;
|
|
8482
|
+
var BASE32_ALPHABET = "abcdefghijklmnopqrstuvwxyz234567";
|
|
8483
|
+
function findSelfPackageDir() {
|
|
8484
|
+
const start = path.dirname(fileURLToPath(import.meta.url));
|
|
8485
|
+
let dir = start;
|
|
8486
|
+
while (true) {
|
|
8487
|
+
const candidate = path.join(dir, "package.json");
|
|
8488
|
+
if (existsSync(candidate)) {
|
|
8489
|
+
if (JSON.parse(readFileSync(candidate, "utf8")).name === SELF_PACKAGE_NAME) return dir;
|
|
8490
|
+
}
|
|
8491
|
+
const parent = path.dirname(dir);
|
|
8492
|
+
if (parent === dir) return start;
|
|
8493
|
+
dir = parent;
|
|
8494
|
+
}
|
|
8495
|
+
}
|
|
8496
|
+
var PACKAGE_DIR = findSelfPackageDir();
|
|
8497
|
+
function sha256Hex(value) {
|
|
8498
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
8499
|
+
}
|
|
8500
|
+
function encodeVarint(value) {
|
|
8501
|
+
const bytes = [];
|
|
8502
|
+
let current = value >>> 0;
|
|
8503
|
+
while (current >= 128) {
|
|
8504
|
+
bytes.push(current & 127 | 128);
|
|
8505
|
+
current >>>= 7;
|
|
8506
|
+
}
|
|
8507
|
+
bytes.push(current);
|
|
8508
|
+
return bytes;
|
|
8509
|
+
}
|
|
8510
|
+
function base32Lower(bytes) {
|
|
8511
|
+
let bits = 0;
|
|
8512
|
+
let value = 0;
|
|
8513
|
+
let output = "";
|
|
8514
|
+
for (const byte of bytes) {
|
|
8515
|
+
value = value << 8 | byte;
|
|
8516
|
+
bits += 8;
|
|
8517
|
+
while (bits >= 5) {
|
|
8518
|
+
output += BASE32_ALPHABET[value >>> bits - 5 & 31];
|
|
8519
|
+
bits -= 5;
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8522
|
+
if (bits > 0) output += BASE32_ALPHABET[value << 5 - bits & 31];
|
|
8523
|
+
return `b${output}`;
|
|
8524
|
+
}
|
|
8525
|
+
function stableStringify(value) {
|
|
8526
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
8527
|
+
if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
8528
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
8529
|
+
}
|
|
8530
|
+
function readPackageVersion(pkgPath, expectedName) {
|
|
8531
|
+
if (!existsSync(pkgPath)) return null;
|
|
8532
|
+
const parsed = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
8533
|
+
if (expectedName && parsed.name !== expectedName) return null;
|
|
8534
|
+
return typeof parsed.version === "string" ? parsed.version : null;
|
|
8535
|
+
}
|
|
8536
|
+
function resolveInstalledPackageVersion(packageName) {
|
|
8537
|
+
const candidates = [];
|
|
8538
|
+
try {
|
|
8539
|
+
candidates.push(path.dirname(require.resolve(packageName)));
|
|
8540
|
+
} catch {}
|
|
8541
|
+
let dir = PACKAGE_DIR;
|
|
8542
|
+
while (true) {
|
|
8543
|
+
candidates.push(path.join(dir, "node_modules", packageName));
|
|
8544
|
+
const parent = path.dirname(dir);
|
|
8545
|
+
if (parent === dir) break;
|
|
8546
|
+
dir = parent;
|
|
8547
|
+
}
|
|
8548
|
+
for (const start of candidates) {
|
|
8549
|
+
let current = start;
|
|
8550
|
+
while (true) {
|
|
8551
|
+
const version = readPackageVersion(path.join(current, "package.json"), packageName);
|
|
8552
|
+
if (version) return version;
|
|
8553
|
+
const parent = path.dirname(current);
|
|
8554
|
+
if (parent === current) break;
|
|
8555
|
+
current = parent;
|
|
8556
|
+
}
|
|
8094
8557
|
}
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
NODE_EXTRA_CA_CERTS: "/etc/ssl/certs/ca-certificates.crt",
|
|
8103
|
-
...envOverrides
|
|
8558
|
+
return null;
|
|
8559
|
+
}
|
|
8560
|
+
function resolvePiJudgeRecipeVersions() {
|
|
8561
|
+
return {
|
|
8562
|
+
pi: resolveInstalledPackageVersion(PI_PACKAGE_NAME),
|
|
8563
|
+
piExtension: readPackageVersion(path.join(PACKAGE_DIR, "package.json"), SELF_PACKAGE_NAME),
|
|
8564
|
+
sdk: resolveInstalledPackageVersion(SDK_PACKAGE_NAME)
|
|
8104
8565
|
};
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
httpHooks,
|
|
8108
|
-
env: vmEnv,
|
|
8109
|
-
...resources?.memory && { memory: resources.memory },
|
|
8110
|
-
...resources?.cpus && { cpus: resources.cpus },
|
|
8111
|
-
vfs: { mounts: { [GUEST_WORKSPACE$1]: workspaceProvider } }
|
|
8112
|
-
});
|
|
8113
|
-
await vm.exec(`sh -c '
|
|
8114
|
-
cp /etc/gondolin/mitm/ca.crt /usr/local/share/ca-certificates/gondolin-mitm.crt
|
|
8115
|
-
update-ca-certificates 2>/dev/null
|
|
8116
|
-
cat /etc/gondolin/mitm/ca.crt >> /etc/ssl/certs/ca-certificates.crt
|
|
8117
|
-
'`);
|
|
8118
|
-
await vm.exec(`sh -c 'echo "nameserver 8.8.8.8
|
|
8119
|
-
nameserver 1.1.1.1" > /etc/resolv.conf'`);
|
|
8120
|
-
const vmAgentDir = `/home/agent/.moltnet/${config.agentName}`;
|
|
8121
|
-
const vmSshDir = `${vmAgentDir}/ssh`;
|
|
8122
|
-
await vm.exec(`mkdir -p ${vmAgentDir}/ssh /home/agent/.pi/agent`);
|
|
8123
|
-
await vm.fs.writeFile("/home/agent/.pi/agent/auth.json", creds.piAuthJson, { mode: 384 });
|
|
8124
|
-
await vm.fs.writeFile(`${vmAgentDir}/moltnet.json`, creds.moltnetJson, { mode: 384 });
|
|
8125
|
-
await vm.fs.writeFile(`${vmAgentDir}/env`, creds.agentEnvRaw, { mode: 384 });
|
|
8126
|
-
if (creds.gitconfig) {
|
|
8127
|
-
const vmSigningKey = `${vmSshDir}/id_ed25519`;
|
|
8128
|
-
let vmGitconfig = creds.gitconfig.replace(/signingKey\s*=\s*.+/g, `signingKey = ${vmSigningKey}`);
|
|
8129
|
-
vmGitconfig = ensureRelativeWorktreePaths(vmGitconfig);
|
|
8130
|
-
await vm.fs.writeFile(`${vmAgentDir}/gitconfig`, vmGitconfig, { mode: 420 });
|
|
8131
|
-
}
|
|
8132
|
-
if (creds.sshPrivateKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519`, creds.sshPrivateKey, { mode: 384 });
|
|
8133
|
-
if (creds.sshPublicKey) await vm.fs.writeFile(`${vmSshDir}/id_ed25519.pub`, creds.sshPublicKey, { mode: 420 });
|
|
8134
|
-
if (creds.allowedSigners) await vm.fs.writeFile(`${vmSshDir}/allowed_signers`, creds.allowedSigners, { mode: 420 });
|
|
8135
|
-
await vm.exec("chown -R agent:agent /home/agent/.pi /home/agent/.moltnet");
|
|
8566
|
+
}
|
|
8567
|
+
function buildPiJudgeRecipeManifest(inputs) {
|
|
8136
8568
|
return {
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8569
|
+
kind: "pi-judge-recipe/v1",
|
|
8570
|
+
versions: {
|
|
8571
|
+
...resolvePiJudgeRecipeVersions(),
|
|
8572
|
+
...inputs.overrides
|
|
8573
|
+
},
|
|
8574
|
+
assets: {
|
|
8575
|
+
promptAsset: inputs.promptAsset ?? null,
|
|
8576
|
+
rubricAsset: inputs.rubricAsset ?? null,
|
|
8577
|
+
skillSourcePath: inputs.skillSourcePath ?? null
|
|
8578
|
+
},
|
|
8579
|
+
hashes: {
|
|
8580
|
+
judgePromptSha256: sha256Hex(inputs.judgePrompt),
|
|
8581
|
+
rubricSha256: sha256Hex(inputs.rubric),
|
|
8582
|
+
skillFragmentSha256: inputs.skillFragment ? sha256Hex(inputs.skillFragment) : null,
|
|
8583
|
+
implementationSha256: inputs.implementationSource ? sha256Hex(inputs.implementationSource) : null
|
|
8584
|
+
}
|
|
8142
8585
|
};
|
|
8143
8586
|
}
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8587
|
+
function computePiJudgeRecipeCid(inputs) {
|
|
8588
|
+
const manifest = buildPiJudgeRecipeManifest(inputs);
|
|
8589
|
+
const manifestBytes = Buffer.from(stableStringify(manifest), "utf8");
|
|
8590
|
+
const digestBytes = createHash("sha256").update(manifestBytes).digest();
|
|
8591
|
+
return {
|
|
8592
|
+
cid: base32Lower(Uint8Array.from([
|
|
8593
|
+
...encodeVarint(CID_VERSION),
|
|
8594
|
+
...encodeVarint(RAW_CODEC),
|
|
8595
|
+
...encodeVarint(SHA2_256_CODE),
|
|
8596
|
+
...encodeVarint(digestBytes.length),
|
|
8597
|
+
...digestBytes
|
|
8598
|
+
])),
|
|
8599
|
+
manifest
|
|
8600
|
+
};
|
|
8154
8601
|
}
|
|
8155
8602
|
//#endregion
|
|
8156
8603
|
//#region ../tasks/src/formats.ts
|
|
@@ -8179,9 +8626,9 @@ if (!FormatRegistry.Has("date-time")) FormatRegistry.Set("date-time", (v) => !Nu
|
|
|
8179
8626
|
* own signed rows and CIDv1 lookup. The schema below is designed to
|
|
8180
8627
|
* carry forward unchanged — only storage and addressing differ.
|
|
8181
8628
|
*
|
|
8182
|
-
* Until Phase 2 lands, `
|
|
8629
|
+
* Until Phase 2 lands, `rubricId` + `version` + `contentHash` are
|
|
8183
8630
|
* informational fields the author fills in; no uniqueness is enforced.
|
|
8184
|
-
* `
|
|
8631
|
+
* `contentHash` is optional in Phase 1 because the *task*'s input_cid
|
|
8185
8632
|
* is the authoritative commitment.
|
|
8186
8633
|
*/
|
|
8187
8634
|
/**
|
|
@@ -8217,12 +8664,12 @@ var RubricCriterion = Type$1.Object({
|
|
|
8217
8664
|
* (stored row `body`); only the addressing mechanism differs.
|
|
8218
8665
|
*/
|
|
8219
8666
|
var Rubric = Type$1.Object({
|
|
8220
|
-
|
|
8667
|
+
rubricId: Type$1.String({ minLength: 1 }),
|
|
8221
8668
|
version: Type$1.String({ minLength: 1 }),
|
|
8222
8669
|
preamble: Type$1.Optional(Type$1.String()),
|
|
8223
8670
|
criteria: Type$1.Array(RubricCriterion, { minItems: 1 }),
|
|
8224
8671
|
scope: Type$1.Optional(Type$1.String()),
|
|
8225
|
-
|
|
8672
|
+
contentHash: Type$1.Optional(Type$1.String())
|
|
8226
8673
|
}, {
|
|
8227
8674
|
$id: "Rubric",
|
|
8228
8675
|
additionalProperties: false
|
|
@@ -8278,25 +8725,25 @@ var AssessBriefCriterion = Type$1.Object({
|
|
|
8278
8725
|
additionalProperties: false
|
|
8279
8726
|
});
|
|
8280
8727
|
var AssessBriefInput = Type$1.Object({
|
|
8281
|
-
|
|
8728
|
+
targetTaskId: Type$1.String({ format: "uuid" }),
|
|
8282
8729
|
criteria: Type$1.Array(AssessBriefCriterion, { minItems: 1 }),
|
|
8283
|
-
|
|
8730
|
+
rubricPreamble: Type$1.Optional(Type$1.String())
|
|
8284
8731
|
}, {
|
|
8285
8732
|
$id: "AssessBriefInput",
|
|
8286
8733
|
additionalProperties: false
|
|
8287
8734
|
});
|
|
8288
8735
|
/** One score line. */
|
|
8289
8736
|
var AssessBriefScore = Type$1.Object({
|
|
8290
|
-
|
|
8737
|
+
criterionId: Type$1.String({ minLength: 1 }),
|
|
8291
8738
|
score: Type$1.Number({
|
|
8292
8739
|
minimum: 0,
|
|
8293
8740
|
maximum: 1
|
|
8294
8741
|
}),
|
|
8295
8742
|
rationale: Type$1.Optional(Type$1.String()),
|
|
8296
8743
|
evidence: Type$1.Optional(Type$1.Object({
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8744
|
+
commitsVerified: Type$1.Number(),
|
|
8745
|
+
commitsTotal: Type$1.Number(),
|
|
8746
|
+
signatureFailures: Type$1.Array(Type$1.String())
|
|
8300
8747
|
}, { additionalProperties: false }))
|
|
8301
8748
|
}, {
|
|
8302
8749
|
$id: "AssessBriefScore",
|
|
@@ -8309,7 +8756,7 @@ var AssessBriefOutput = Type$1.Object({
|
|
|
8309
8756
|
maximum: 1
|
|
8310
8757
|
}),
|
|
8311
8758
|
verdict: Type$1.String({ minLength: 1 }),
|
|
8312
|
-
|
|
8759
|
+
judgeModel: Type$1.Optional(Type$1.String())
|
|
8313
8760
|
}, {
|
|
8314
8761
|
$id: "AssessBriefOutput",
|
|
8315
8762
|
additionalProperties: false
|
|
@@ -8340,15 +8787,15 @@ var EntryTypeFilter = Type$1.Union([
|
|
|
8340
8787
|
Type$1.Literal("reflection")
|
|
8341
8788
|
]);
|
|
8342
8789
|
var CuratePackInput = Type$1.Object({
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8790
|
+
diaryId: Type$1.String({ format: "uuid" }),
|
|
8791
|
+
taskPrompt: Type$1.String({ minLength: 1 }),
|
|
8792
|
+
entryTypes: Type$1.Optional(Type$1.Array(EntryTypeFilter, { minItems: 1 })),
|
|
8793
|
+
tagFilters: Type$1.Optional(Type$1.Object({
|
|
8347
8794
|
include: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8348
8795
|
exclude: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8349
8796
|
prefix: Type$1.Optional(Type$1.String())
|
|
8350
8797
|
}, { additionalProperties: false })),
|
|
8351
|
-
|
|
8798
|
+
tokenBudget: Type$1.Optional(Type$1.Number({ minimum: 500 })),
|
|
8352
8799
|
recipe: Type$1.Optional(Type$1.Union([Type$1.Literal("topic-focused-v1"), Type$1.Literal("scope-inventory-v1")]))
|
|
8353
8800
|
}, {
|
|
8354
8801
|
$id: "CuratePackInput",
|
|
@@ -8360,18 +8807,18 @@ var CuratePackInput = Type$1.Object({
|
|
|
8360
8807
|
* is the receipt.
|
|
8361
8808
|
*/
|
|
8362
8809
|
var CuratePackOutput = Type$1.Object({
|
|
8363
|
-
|
|
8364
|
-
|
|
8810
|
+
packId: Type$1.String({ format: "uuid" }),
|
|
8811
|
+
packCid: Type$1.String({ minLength: 1 }),
|
|
8365
8812
|
entries: Type$1.Array(Type$1.Object({
|
|
8366
|
-
|
|
8813
|
+
entryId: Type$1.String({ format: "uuid" }),
|
|
8367
8814
|
rank: Type$1.Number({ minimum: 1 }),
|
|
8368
8815
|
rationale: Type$1.String({ minLength: 1 })
|
|
8369
8816
|
}, { additionalProperties: false }), { minItems: 1 }),
|
|
8370
|
-
|
|
8817
|
+
recipeParams: Type$1.Record(Type$1.String(), Type$1.Unknown()),
|
|
8371
8818
|
checkpoints: Type$1.Optional(Type$1.Array(Type$1.Object({
|
|
8372
8819
|
phase: Type$1.String({ minLength: 1 }),
|
|
8373
|
-
|
|
8374
|
-
|
|
8820
|
+
candidateIds: Type$1.Array(Type$1.String({ format: "uuid" })),
|
|
8821
|
+
droppedIds: Type$1.Optional(Type$1.Array(Type$1.String({ format: "uuid" }))),
|
|
8375
8822
|
notes: Type$1.String({ minLength: 1 })
|
|
8376
8823
|
}, { additionalProperties: false }))),
|
|
8377
8824
|
summary: Type$1.String({ minLength: 1 })
|
|
@@ -8392,9 +8839,9 @@ var FULFILL_BRIEF_TYPE = "fulfill_brief";
|
|
|
8392
8839
|
var FulfillBriefInput = Type$1.Object({
|
|
8393
8840
|
brief: Type$1.String({ minLength: 1 }),
|
|
8394
8841
|
title: Type$1.Optional(Type$1.String()),
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8842
|
+
acceptanceCriteria: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8843
|
+
seedFiles: Type$1.Optional(Type$1.Array(Type$1.String())),
|
|
8844
|
+
scopeHint: Type$1.Optional(Type$1.String())
|
|
8398
8845
|
}, {
|
|
8399
8846
|
$id: "FulfillBriefInput",
|
|
8400
8847
|
additionalProperties: false
|
|
@@ -8408,10 +8855,10 @@ var FulfillBriefOutput = Type$1.Object({
|
|
|
8408
8855
|
commits: Type$1.Array(Type$1.Object({
|
|
8409
8856
|
sha: Type$1.String({ minLength: 7 }),
|
|
8410
8857
|
message: Type$1.String(),
|
|
8411
|
-
|
|
8858
|
+
diaryEntryId: Type$1.Union([Type$1.String({ format: "uuid" }), Type$1.Null()])
|
|
8412
8859
|
}, { additionalProperties: false })),
|
|
8413
|
-
|
|
8414
|
-
|
|
8860
|
+
pullRequestUrl: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
8861
|
+
diaryEntryIds: Type$1.Array(Type$1.String({ format: "uuid" })),
|
|
8415
8862
|
summary: Type$1.String({ minLength: 1 })
|
|
8416
8863
|
}, {
|
|
8417
8864
|
$id: "FulfillBriefOutput",
|
|
@@ -8442,8 +8889,8 @@ var FulfillBriefOutput = Type$1.Object({
|
|
|
8442
8889
|
*/
|
|
8443
8890
|
var JUDGE_PACK_TYPE = "judge_pack";
|
|
8444
8891
|
var JudgePackInput = Type$1.Object({
|
|
8445
|
-
|
|
8446
|
-
|
|
8892
|
+
renderedPackId: Type$1.String({ format: "uuid" }),
|
|
8893
|
+
sourcePackId: Type$1.String({ format: "uuid" }),
|
|
8447
8894
|
rubric: Rubric
|
|
8448
8895
|
}, {
|
|
8449
8896
|
$id: "JudgePackInput",
|
|
@@ -8451,7 +8898,7 @@ var JudgePackInput = Type$1.Object({
|
|
|
8451
8898
|
});
|
|
8452
8899
|
/** One scored criterion. Mirrors `AssessBriefScore`. */
|
|
8453
8900
|
var JudgePackScore = Type$1.Object({
|
|
8454
|
-
|
|
8901
|
+
criterionId: Type$1.String({ minLength: 1 }),
|
|
8455
8902
|
score: Type$1.Number({
|
|
8456
8903
|
minimum: 0,
|
|
8457
8904
|
maximum: 1
|
|
@@ -8469,8 +8916,8 @@ var JudgePackOutput = Type$1.Object({
|
|
|
8469
8916
|
maximum: 1
|
|
8470
8917
|
}),
|
|
8471
8918
|
verdict: Type$1.String({ minLength: 1 }),
|
|
8472
|
-
|
|
8473
|
-
|
|
8919
|
+
judgeModel: Type$1.Optional(Type$1.String()),
|
|
8920
|
+
rendererBinaryCid: Type$1.Optional(Type$1.Union([Type$1.String(), Type$1.Null()]))
|
|
8474
8921
|
}, {
|
|
8475
8922
|
$id: "JudgePackOutput",
|
|
8476
8923
|
additionalProperties: false
|
|
@@ -8494,7 +8941,7 @@ var JudgePackOutput = Type$1.Object({
|
|
|
8494
8941
|
*/
|
|
8495
8942
|
var RENDER_PACK_TYPE = "render_pack";
|
|
8496
8943
|
var RenderPackInput = Type$1.Object({
|
|
8497
|
-
|
|
8944
|
+
packId: Type$1.String({ format: "uuid" }),
|
|
8498
8945
|
persist: Type$1.Optional(Type$1.Boolean()),
|
|
8499
8946
|
pinned: Type$1.Optional(Type$1.Boolean())
|
|
8500
8947
|
}, {
|
|
@@ -8502,11 +8949,11 @@ var RenderPackInput = Type$1.Object({
|
|
|
8502
8949
|
additionalProperties: false
|
|
8503
8950
|
});
|
|
8504
8951
|
var RenderPackOutput = Type$1.Object({
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8952
|
+
renderedPackId: Type$1.Union([Type$1.String({ format: "uuid" }), Type$1.Null()]),
|
|
8953
|
+
renderedCid: Type$1.String({ minLength: 1 }),
|
|
8954
|
+
renderMethod: Type$1.String({ minLength: 1 }),
|
|
8955
|
+
byteSize: Type$1.Number({ minimum: 0 }),
|
|
8956
|
+
entriesRendered: Type$1.Number({ minimum: 0 }),
|
|
8510
8957
|
summary: Type$1.String({ minLength: 1 })
|
|
8511
8958
|
}, {
|
|
8512
8959
|
$id: "RenderPackOutput",
|
|
@@ -8578,6 +9025,30 @@ new Proxy({}, { get(_, prop) {
|
|
|
8578
9025
|
return getTaskTypeRegistry().get(prop);
|
|
8579
9026
|
} });
|
|
8580
9027
|
//#endregion
|
|
9028
|
+
//#region ../tasks/src/validation.ts
|
|
9029
|
+
function getTaskTypeEntry(taskType) {
|
|
9030
|
+
const taskTypes = BUILT_IN_TASK_TYPES;
|
|
9031
|
+
if (!Object.prototype.hasOwnProperty.call(taskTypes, taskType)) return;
|
|
9032
|
+
return taskTypes[taskType];
|
|
9033
|
+
}
|
|
9034
|
+
function formatField(prefix, path) {
|
|
9035
|
+
return path ? `${prefix}${path}` : prefix;
|
|
9036
|
+
}
|
|
9037
|
+
function schemaErrors(prefix, schema, value) {
|
|
9038
|
+
return [...Value.Errors(schema, value)].map((error) => ({
|
|
9039
|
+
field: formatField(prefix, error.path),
|
|
9040
|
+
message: error.message
|
|
9041
|
+
}));
|
|
9042
|
+
}
|
|
9043
|
+
function validateTaskOutput(taskType, output) {
|
|
9044
|
+
const entry = getTaskTypeEntry(taskType);
|
|
9045
|
+
if (!entry) return [{
|
|
9046
|
+
field: "taskType",
|
|
9047
|
+
message: `Unknown task type: ${taskType}`
|
|
9048
|
+
}];
|
|
9049
|
+
return schemaErrors("output", entry.outputSchema, output);
|
|
9050
|
+
}
|
|
9051
|
+
//#endregion
|
|
8581
9052
|
//#region ../tasks/src/wire.ts
|
|
8582
9053
|
/**
|
|
8583
9054
|
* Wire-format types for the MoltNet Task model.
|
|
@@ -8589,7 +9060,7 @@ new Proxy({}, { get(_, prop) {
|
|
|
8589
9060
|
* - `TaskReporter` output records (PR 0)
|
|
8590
9061
|
*
|
|
8591
9062
|
* Invariant: every property on `Task` is type-neutral (applies to all
|
|
8592
|
-
* `
|
|
9063
|
+
* `taskType`s). Type-specific payloads live inside `input` / `output`
|
|
8593
9064
|
* JSONB, validated against schemas registered under `task_types`.
|
|
8594
9065
|
*
|
|
8595
9066
|
* Identity rule:
|
|
@@ -8632,8 +9103,8 @@ var IsoTimestamp = Type$1.String({ format: "date-time" });
|
|
|
8632
9103
|
* Embedded in `tasks.references` JSONB array.
|
|
8633
9104
|
*/
|
|
8634
9105
|
var TaskRef = Type$1.Object({
|
|
8635
|
-
|
|
8636
|
-
|
|
9106
|
+
taskId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9107
|
+
outputCid: Cid,
|
|
8637
9108
|
role: Type$1.Union([
|
|
8638
9109
|
Type$1.Literal("judged_work"),
|
|
8639
9110
|
Type$1.Literal("reviewed_diff"),
|
|
@@ -8662,11 +9133,11 @@ var TaskRef = Type$1.Object({
|
|
|
8662
9133
|
* `TaskOutput.usage` for convenience.
|
|
8663
9134
|
*/
|
|
8664
9135
|
var TaskUsage = Type$1.Object({
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
9136
|
+
inputTokens: Type$1.Integer({ minimum: 0 }),
|
|
9137
|
+
outputTokens: Type$1.Integer({ minimum: 0 }),
|
|
9138
|
+
cacheReadTokens: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
9139
|
+
cacheWriteTokens: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
9140
|
+
toolCalls: Type$1.Optional(Type$1.Integer({ minimum: 0 })),
|
|
8670
9141
|
model: Type$1.Optional(Type$1.String()),
|
|
8671
9142
|
provider: Type$1.Optional(Type$1.String())
|
|
8672
9143
|
}, {
|
|
@@ -8686,62 +9157,65 @@ var TaskError = Type$1.Object({
|
|
|
8686
9157
|
additionalProperties: false
|
|
8687
9158
|
});
|
|
8688
9159
|
Type$1.Object({
|
|
8689
|
-
|
|
8690
|
-
|
|
9160
|
+
agentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9161
|
+
humanId: Type$1.Union([Uuid, Type$1.Null()])
|
|
8691
9162
|
}, {
|
|
8692
9163
|
$id: "ActorPair",
|
|
8693
9164
|
additionalProperties: false
|
|
8694
9165
|
});
|
|
8695
9166
|
Type$1.Object({
|
|
8696
9167
|
id: Uuid,
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
9168
|
+
taskType: Type$1.String({ minLength: 1 }),
|
|
9169
|
+
teamId: Uuid,
|
|
9170
|
+
diaryId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9171
|
+
outputKind: OutputKind,
|
|
8701
9172
|
input: Type$1.Record(Type$1.String(), Type$1.Unknown()),
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
9173
|
+
inputSchemaCid: Cid,
|
|
9174
|
+
inputCid: Cid,
|
|
9175
|
+
criteriaCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8705
9176
|
references: Type$1.Array(TaskRef),
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
9177
|
+
correlationId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9178
|
+
imposedByAgentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9179
|
+
imposedByHumanId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9180
|
+
acceptedAttemptN: Type$1.Union([Type$1.Number(), Type$1.Null()]),
|
|
8710
9181
|
status: TaskStatus,
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
9182
|
+
queuedAt: IsoTimestamp,
|
|
9183
|
+
completedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9184
|
+
expiresAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9185
|
+
cancelledByAgentId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9186
|
+
cancelledByHumanId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9187
|
+
cancelReason: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
9188
|
+
maxAttempts: Type$1.Number({ minimum: 1 })
|
|
8718
9189
|
}, {
|
|
8719
9190
|
$id: "Task",
|
|
8720
9191
|
additionalProperties: false
|
|
8721
9192
|
});
|
|
8722
9193
|
Type$1.Object({
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
9194
|
+
taskId: Uuid,
|
|
9195
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
9196
|
+
claimedByAgentId: Uuid,
|
|
9197
|
+
runtimeId: Type$1.Union([Uuid, Type$1.Null()]),
|
|
9198
|
+
claimedAt: IsoTimestamp,
|
|
9199
|
+
startedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
9200
|
+
completedAt: Type$1.Union([IsoTimestamp, Type$1.Null()]),
|
|
8730
9201
|
status: TaskAttemptStatus,
|
|
8731
9202
|
output: Type$1.Union([Type$1.Record(Type$1.String(), Type$1.Unknown()), Type$1.Null()]),
|
|
8732
|
-
|
|
9203
|
+
outputCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8733
9204
|
error: Type$1.Union([TaskError, Type$1.Null()]),
|
|
8734
9205
|
usage: Type$1.Union([TaskUsage, Type$1.Null()]),
|
|
8735
|
-
|
|
8736
|
-
|
|
9206
|
+
contentSignature: Type$1.Union([Type$1.String(), Type$1.Null()]),
|
|
9207
|
+
signedAt: Type$1.Union([IsoTimestamp, Type$1.Null()])
|
|
8737
9208
|
}, {
|
|
8738
9209
|
$id: "TaskAttempt",
|
|
8739
9210
|
additionalProperties: false
|
|
8740
9211
|
});
|
|
8741
9212
|
Type$1.Object({
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
seq: Type$1.Number({
|
|
9213
|
+
taskId: Uuid,
|
|
9214
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
9215
|
+
seq: Type$1.Number({
|
|
9216
|
+
minimum: 0,
|
|
9217
|
+
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."
|
|
9218
|
+
}),
|
|
8745
9219
|
timestamp: IsoTimestamp,
|
|
8746
9220
|
kind: TaskMessageKind,
|
|
8747
9221
|
payload: Type$1.Record(Type$1.String(), Type$1.Unknown())
|
|
@@ -8750,34 +9224,34 @@ Type$1.Object({
|
|
|
8750
9224
|
additionalProperties: false
|
|
8751
9225
|
});
|
|
8752
9226
|
Type$1.Object({
|
|
8753
|
-
|
|
8754
|
-
|
|
9227
|
+
taskId: Uuid,
|
|
9228
|
+
attemptN: Type$1.Number({ minimum: 1 }),
|
|
8755
9229
|
status: Type$1.Union([
|
|
8756
9230
|
Type$1.Literal("completed"),
|
|
8757
9231
|
Type$1.Literal("failed"),
|
|
8758
9232
|
Type$1.Literal("cancelled")
|
|
8759
9233
|
]),
|
|
8760
9234
|
output: Type$1.Union([Type$1.Record(Type$1.String(), Type$1.Unknown()), Type$1.Null()]),
|
|
8761
|
-
|
|
9235
|
+
outputCid: Type$1.Union([Cid, Type$1.Null()]),
|
|
8762
9236
|
usage: TaskUsage,
|
|
8763
|
-
|
|
9237
|
+
durationMs: Type$1.Number({ minimum: 0 }),
|
|
8764
9238
|
error: Type$1.Optional(TaskError),
|
|
8765
|
-
|
|
9239
|
+
contentSignature: Type$1.Optional(Type$1.String())
|
|
8766
9240
|
}, {
|
|
8767
9241
|
$id: "TaskOutput",
|
|
8768
9242
|
additionalProperties: false
|
|
8769
9243
|
});
|
|
8770
9244
|
Type$1.Object({
|
|
8771
|
-
|
|
8772
|
-
|
|
9245
|
+
runtimeId: Uuid,
|
|
9246
|
+
agentId: Uuid,
|
|
8773
9247
|
timestamp: IsoTimestamp,
|
|
8774
9248
|
status: Type$1.Union([
|
|
8775
9249
|
Type$1.Literal("idle"),
|
|
8776
9250
|
Type$1.Literal("busy"),
|
|
8777
9251
|
Type$1.Literal("draining")
|
|
8778
9252
|
]),
|
|
8779
|
-
|
|
8780
|
-
|
|
9253
|
+
activeTaskIds: Type$1.Array(Uuid),
|
|
9254
|
+
supportedTaskTypes: Type$1.Array(Type$1.String())
|
|
8781
9255
|
}, {
|
|
8782
9256
|
$id: "RuntimeHeartbeat",
|
|
8783
9257
|
additionalProperties: false
|
|
@@ -8798,10 +9272,10 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8798
9272
|
...ctx.target.diaryEntryIds.map((id) => `- ${id}`),
|
|
8799
9273
|
""
|
|
8800
9274
|
].join("\n") : "";
|
|
8801
|
-
const preambleSection = input.
|
|
9275
|
+
const preambleSection = input.rubricPreamble ? [
|
|
8802
9276
|
"### Rubric preamble",
|
|
8803
9277
|
"",
|
|
8804
|
-
input.
|
|
9278
|
+
input.rubricPreamble,
|
|
8805
9279
|
""
|
|
8806
9280
|
].join("\n") : "";
|
|
8807
9281
|
return [
|
|
@@ -8832,12 +9306,12 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8832
9306
|
"",
|
|
8833
9307
|
"- `llm_judged`: score 0..1 continuous. `rationale` REQUIRED (2–4 sentences).",
|
|
8834
9308
|
"- `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.
|
|
9309
|
+
"- `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
9310
|
"",
|
|
8837
9311
|
"### Final output",
|
|
8838
9312
|
"",
|
|
8839
9313
|
"Emit a JSON object matching `AssessBriefOutput`:",
|
|
8840
|
-
" { \"scores\": [{
|
|
9314
|
+
" { \"scores\": [{criterionId, score, rationale?, evidence?}], \"composite\", \"verdict\", \"judgeModel\"? }",
|
|
8841
9315
|
"`composite` = Σ(weight_i × score_i) recomputed. The runtime will reject a mismatch.",
|
|
8842
9316
|
"Write a signed diary entry (tags: \"judgment\", \"assess_brief\") capturing the rationale before emitting the JSON."
|
|
8843
9317
|
].filter(Boolean).join("\n");
|
|
@@ -8859,7 +9333,7 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8859
9333
|
* N isolated `createAgentSession` children (one per tag cluster or
|
|
8860
9334
|
* entry_type axis the curator picks after recon), each with a narrow
|
|
8861
9335
|
* tool subset and a turn cap, and returns compressed summaries. Parent
|
|
8862
|
-
* curator keeps a warm context and only sees {
|
|
9336
|
+
* curator keeps a warm context and only sees {candidateIds, notes}
|
|
8863
9337
|
* per probe — mirrors the fan-out pattern pi-mono SDK example #13
|
|
8864
9338
|
* (session runtime) + #05 (custom tools) makes possible. Until that
|
|
8865
9339
|
* lands, the `checkpoints[]` output field is the fallback: curator
|
|
@@ -8867,7 +9341,7 @@ function buildAssessBriefPrompt(input, ctx) {
|
|
|
8867
9341
|
* resume without replaying the tool history.
|
|
8868
9342
|
*/
|
|
8869
9343
|
function buildCuratePackPrompt(input, ctx) {
|
|
8870
|
-
const {
|
|
9344
|
+
const { diaryId, taskPrompt, entryTypes, tagFilters, tokenBudget, recipe } = input;
|
|
8871
9345
|
const effectiveEntryTypes = entryTypes ?? [
|
|
8872
9346
|
"semantic",
|
|
8873
9347
|
"episodic",
|
|
@@ -8954,7 +9428,7 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8954
9428
|
"",
|
|
8955
9429
|
"The tool returns a JSON payload whose top-level fields are `packId` and",
|
|
8956
9430
|
"`packCid` (NOT `id`). Copy those exact UUID/CID strings verbatim into",
|
|
8957
|
-
"`
|
|
9431
|
+
"`packId` and `packCid` in your final output — do not substitute an",
|
|
8958
9432
|
"entry id, do not reformat, do not fabricate a UUID.",
|
|
8959
9433
|
"",
|
|
8960
9434
|
"## Hard constraints",
|
|
@@ -8971,14 +9445,14 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8971
9445
|
"Write to stdout a JSON object matching `CuratePackOutput`:",
|
|
8972
9446
|
"```",
|
|
8973
9447
|
"{",
|
|
8974
|
-
" \"
|
|
8975
|
-
" \"
|
|
9448
|
+
" \"packId\": \"<uuid>\",",
|
|
9449
|
+
" \"packCid\": \"<cid>\",",
|
|
8976
9450
|
" \"entries\": [",
|
|
8977
|
-
" { \"
|
|
9451
|
+
" { \"entryId\": \"<uuid>\", \"rank\": 1, \"rationale\": \"<why>\" }",
|
|
8978
9452
|
" ],",
|
|
8979
|
-
" \"
|
|
9453
|
+
" \"recipeParams\": { \"recipe\": \"...\", \"prompt\": \"...\", ... },",
|
|
8980
9454
|
" \"checkpoints\": [",
|
|
8981
|
-
" { \"phase\": \"recon\", \"
|
|
9455
|
+
" { \"phase\": \"recon\", \"candidateIds\": [...], \"droppedIds\": [...], \"notes\": \"...\" }",
|
|
8982
9456
|
" ],",
|
|
8983
9457
|
" \"summary\": \"<2-4 sentences: what you looked for, how you narrowed, what defines the final set>\"",
|
|
8984
9458
|
"}",
|
|
@@ -8996,7 +9470,7 @@ function buildCuratePackPrompt(input, ctx) {
|
|
|
8996
9470
|
* is told to inspect them itself.
|
|
8997
9471
|
*/
|
|
8998
9472
|
function buildFulfillBriefPrompt(input, ctx) {
|
|
8999
|
-
const { brief, title,
|
|
9473
|
+
const { brief, title, acceptanceCriteria, seedFiles, scopeHint } = input;
|
|
9000
9474
|
const criteriaSection = acceptanceCriteria?.length ? [
|
|
9001
9475
|
"### Acceptance criteria",
|
|
9002
9476
|
"",
|
|
@@ -9045,14 +9519,14 @@ function buildFulfillBriefPrompt(input, ctx) {
|
|
|
9045
9519
|
"### Final output",
|
|
9046
9520
|
"",
|
|
9047
9521
|
"When done, write to stdout a JSON object with shape matching `FulfillBriefOutput`:",
|
|
9048
|
-
" { \"branch\", \"commits\": [{sha, message,
|
|
9522
|
+
" { \"branch\", \"commits\": [{sha, message, diaryEntryId}], \"pullRequestUrl\", \"diaryEntryIds\", \"summary\" }",
|
|
9049
9523
|
"The runtime parses this as the structured task output. Failing to emit it is a failure."
|
|
9050
9524
|
].filter(Boolean).join("\n");
|
|
9051
9525
|
}
|
|
9052
9526
|
//#endregion
|
|
9053
9527
|
//#region ../agent-runtime/src/prompts/judge-pack.ts
|
|
9054
9528
|
function buildJudgePackPrompt(input, ctx) {
|
|
9055
|
-
const {
|
|
9529
|
+
const { renderedPackId, sourcePackId, rubric } = input;
|
|
9056
9530
|
const criteriaList = rubric.criteria.map((c, i) => `${i + 1}. **${c.id}** (weight ${c.weight}, scoring: \`${c.scoring}\`) — ${c.description}`).join("\n");
|
|
9057
9531
|
const preambleSection = rubric.preamble ? [
|
|
9058
9532
|
"### Rubric preamble",
|
|
@@ -9075,7 +9549,7 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9075
9549
|
"",
|
|
9076
9550
|
`- **Rendered pack**: \`${renderedPackId}\``,
|
|
9077
9551
|
`- **Source pack**: \`${sourcePackId}\``,
|
|
9078
|
-
`- **Rubric**: \`${rubric.
|
|
9552
|
+
`- **Rubric**: \`${rubric.rubricId}\` v${rubric.version}`,
|
|
9079
9553
|
"",
|
|
9080
9554
|
preambleSection,
|
|
9081
9555
|
"## Workflow",
|
|
@@ -9114,12 +9588,12 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9114
9588
|
" non-empty `contentSignature`. If `required_signed_total` is 0,",
|
|
9115
9589
|
" score = 1. Populate `evidence` with `{ entries_verified,",
|
|
9116
9590
|
" entries_total, required_signed_total, required_signed_ok,",
|
|
9117
|
-
"
|
|
9591
|
+
" signatureFailures: [entryIds] }` where `signatureFailures` lists",
|
|
9118
9592
|
" ONLY the REQUIRED-SIGNED entries that lack a signature.",
|
|
9119
9593
|
"- `deterministic_coverage_check`: for every source entry, check",
|
|
9120
|
-
" whether its `
|
|
9594
|
+
" whether its `entryId` (or a stable reference like title + CID",
|
|
9121
9595
|
" prefix) appears in the rendered `content`. Score 1 iff coverage is",
|
|
9122
|
-
" complete; otherwise 0. Populate `evidence` with `{ covered, total, missing: [
|
|
9596
|
+
" complete; otherwise 0. Populate `evidence` with `{ covered, total, missing: [entryIds] }`.",
|
|
9123
9597
|
"",
|
|
9124
9598
|
"## Constraints",
|
|
9125
9599
|
"",
|
|
@@ -9133,17 +9607,17 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9133
9607
|
"Write to stdout a JSON object matching `JudgePackOutput`:",
|
|
9134
9608
|
"```",
|
|
9135
9609
|
"{",
|
|
9136
|
-
" \"scores\": [{\"
|
|
9610
|
+
" \"scores\": [{\"criterionId\": \"...\", \"score\": 0.0, \"rationale\": \"...\", \"evidence\": {...}}],",
|
|
9137
9611
|
" \"composite\": <sum-of-weighted-scores>,",
|
|
9138
9612
|
" \"verdict\": \"<1-3 sentence overall>\",",
|
|
9139
|
-
" \"
|
|
9140
|
-
" \"
|
|
9613
|
+
" \"judgeModel\": \"<provider:model>\",",
|
|
9614
|
+
" \"rendererBinaryCid\": \"<cid-string-only-if-available>\"",
|
|
9141
9615
|
"}",
|
|
9142
9616
|
"```",
|
|
9143
|
-
"Omit `
|
|
9617
|
+
"Omit `rendererBinaryCid` entirely when no binary CID is exposed by",
|
|
9144
9618
|
"`moltnet_rendered_pack_get`. Do NOT emit `null` — the field is optional",
|
|
9145
9619
|
"and absence is the correct representation when unavailable.",
|
|
9146
|
-
`Write a signed diary entry (tags: \`judgment\`, \`judge_pack\`, \`rubric:${rubric.
|
|
9620
|
+
`Write a signed diary entry (tags: \`judgment\`, \`judge_pack\`, \`rubric:${rubric.rubricId}\`) capturing the rationale before`,
|
|
9147
9621
|
"emitting the JSON."
|
|
9148
9622
|
].filter((l) => l !== null).join("\n");
|
|
9149
9623
|
}
|
|
@@ -9154,7 +9628,7 @@ function buildJudgePackPrompt(input, ctx) {
|
|
|
9154
9628
|
* wraps `moltnet_pack_render` and emits the receipt.
|
|
9155
9629
|
*/
|
|
9156
9630
|
function buildRenderPackPrompt(input, ctx) {
|
|
9157
|
-
const {
|
|
9631
|
+
const { packId, persist = true, pinned = false } = input;
|
|
9158
9632
|
return [
|
|
9159
9633
|
"# Render Pack Agent",
|
|
9160
9634
|
"",
|
|
@@ -9194,11 +9668,11 @@ function buildRenderPackPrompt(input, ctx) {
|
|
|
9194
9668
|
"Write to stdout a JSON object matching `RenderPackOutput`:",
|
|
9195
9669
|
"```",
|
|
9196
9670
|
"{",
|
|
9197
|
-
" \"
|
|
9198
|
-
" \"
|
|
9199
|
-
" \"
|
|
9200
|
-
" \"
|
|
9201
|
-
" \"
|
|
9671
|
+
" \"renderedPackId\": \"<uuid-or-null>\",",
|
|
9672
|
+
" \"renderedCid\": \"<cid>\",",
|
|
9673
|
+
" \"renderMethod\": \"<label>\",",
|
|
9674
|
+
" \"byteSize\": <int>,",
|
|
9675
|
+
" \"entriesRendered\": <int>,",
|
|
9202
9676
|
" \"summary\": \"<1-3 sentence recap>\"",
|
|
9203
9677
|
"}",
|
|
9204
9678
|
"```",
|
|
@@ -9208,11 +9682,11 @@ function buildRenderPackPrompt(input, ctx) {
|
|
|
9208
9682
|
//#endregion
|
|
9209
9683
|
//#region ../agent-runtime/src/prompts/index.ts
|
|
9210
9684
|
/**
|
|
9211
|
-
* Resolve the correct prompt builder for `task.
|
|
9685
|
+
* Resolve the correct prompt builder for `task.taskType` and invoke it.
|
|
9212
9686
|
* Throws if the type is unknown or the input fails TypeBox validation.
|
|
9213
9687
|
*/
|
|
9214
9688
|
function buildPromptForTask(task, ctx) {
|
|
9215
|
-
switch (task.
|
|
9689
|
+
switch (task.taskType) {
|
|
9216
9690
|
case FULFILL_BRIEF_TYPE:
|
|
9217
9691
|
if (!Value.Check(FulfillBriefInput, task.input)) {
|
|
9218
9692
|
const errors = [...Value.Errors(FulfillBriefInput, task.input)];
|
|
@@ -9262,8 +9736,100 @@ function buildPromptForTask(task, ctx) {
|
|
|
9262
9736
|
diaryId: ctx.diaryId,
|
|
9263
9737
|
taskId: ctx.taskId
|
|
9264
9738
|
});
|
|
9265
|
-
default: throw new Error(`No prompt builder registered for
|
|
9739
|
+
default: throw new Error(`No prompt builder registered for taskType="${task.taskType}"`);
|
|
9740
|
+
}
|
|
9741
|
+
}
|
|
9742
|
+
//#endregion
|
|
9743
|
+
//#region src/runtime/task-output.ts
|
|
9744
|
+
async function parseStructuredTaskOutput(assistantText, taskType) {
|
|
9745
|
+
const extracted = extractJsonObject(assistantText);
|
|
9746
|
+
if (!extracted) return {
|
|
9747
|
+
output: null,
|
|
9748
|
+
outputCid: null,
|
|
9749
|
+
error: {
|
|
9750
|
+
code: "output_missing",
|
|
9751
|
+
message: "Agent did not emit a parseable JSON object as its final message."
|
|
9752
|
+
}
|
|
9753
|
+
};
|
|
9754
|
+
const errors = validateTaskOutput(taskType, extracted);
|
|
9755
|
+
if (errors.length > 0) {
|
|
9756
|
+
const details = errors.slice(0, 3).map((error) => `${error.field}: ${error.message}`);
|
|
9757
|
+
const [firstError] = errors;
|
|
9758
|
+
return {
|
|
9759
|
+
output: null,
|
|
9760
|
+
outputCid: null,
|
|
9761
|
+
error: {
|
|
9762
|
+
code: firstError?.field === "taskType" ? "unknown_task_type" : "output_validation_failed",
|
|
9763
|
+
message: `Output failed schema validation: ${details.join("; ")}`
|
|
9764
|
+
}
|
|
9765
|
+
};
|
|
9766
|
+
}
|
|
9767
|
+
try {
|
|
9768
|
+
return {
|
|
9769
|
+
output: extracted,
|
|
9770
|
+
outputCid: await computeJsonCid(extracted),
|
|
9771
|
+
error: null
|
|
9772
|
+
};
|
|
9773
|
+
} catch (error) {
|
|
9774
|
+
return {
|
|
9775
|
+
output: null,
|
|
9776
|
+
outputCid: null,
|
|
9777
|
+
error: {
|
|
9778
|
+
code: "output_cid_compute_failed",
|
|
9779
|
+
message: `Validated output could not be canonicalized: ${error instanceof Error ? error.message : String(error)}`
|
|
9780
|
+
}
|
|
9781
|
+
};
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
/**
|
|
9785
|
+
* Find the last balanced top-level JSON object in `text` and parse it.
|
|
9786
|
+
* Tolerates markdown fences and leading prose. Returns null if parsing fails.
|
|
9787
|
+
*/
|
|
9788
|
+
function extractJsonObject(text) {
|
|
9789
|
+
if (!text) return null;
|
|
9790
|
+
const fenceMatch = /```(?:json)?\s*([\s\S]*?)```/gi;
|
|
9791
|
+
const candidates = [];
|
|
9792
|
+
for (const m of text.matchAll(fenceMatch)) candidates.push(m[1]);
|
|
9793
|
+
const scanForObject = (s) => {
|
|
9794
|
+
let depth = 0;
|
|
9795
|
+
let start = -1;
|
|
9796
|
+
let lastComplete = null;
|
|
9797
|
+
let inString = false;
|
|
9798
|
+
let escape = false;
|
|
9799
|
+
for (let i = 0; i < s.length; i++) {
|
|
9800
|
+
const ch = s[i];
|
|
9801
|
+
if (inString) {
|
|
9802
|
+
if (escape) escape = false;
|
|
9803
|
+
else if (ch === "\\") escape = true;
|
|
9804
|
+
else if (ch === "\"") inString = false;
|
|
9805
|
+
continue;
|
|
9806
|
+
}
|
|
9807
|
+
if (ch === "\"") {
|
|
9808
|
+
inString = true;
|
|
9809
|
+
continue;
|
|
9810
|
+
}
|
|
9811
|
+
if (ch === "{") {
|
|
9812
|
+
if (depth === 0) start = i;
|
|
9813
|
+
depth++;
|
|
9814
|
+
} else if (ch === "}") {
|
|
9815
|
+
depth--;
|
|
9816
|
+
if (depth === 0 && start !== -1) {
|
|
9817
|
+
lastComplete = s.slice(start, i + 1);
|
|
9818
|
+
start = -1;
|
|
9819
|
+
}
|
|
9820
|
+
}
|
|
9821
|
+
}
|
|
9822
|
+
return lastComplete;
|
|
9823
|
+
};
|
|
9824
|
+
candidates.push(text);
|
|
9825
|
+
for (let i = candidates.length - 1; i >= 0; i--) {
|
|
9826
|
+
const obj = scanForObject(candidates[i]);
|
|
9827
|
+
if (!obj) continue;
|
|
9828
|
+
try {
|
|
9829
|
+
return JSON.parse(obj);
|
|
9830
|
+
} catch {}
|
|
9266
9831
|
}
|
|
9832
|
+
return null;
|
|
9267
9833
|
}
|
|
9268
9834
|
//#endregion
|
|
9269
9835
|
//#region src/runtime/execute-pi-task.ts
|
|
@@ -9290,14 +9856,14 @@ function buildPromptForTask(task, ctx) {
|
|
|
9290
9856
|
*/
|
|
9291
9857
|
function createPiTaskExecutor(opts) {
|
|
9292
9858
|
let cachedCheckpoint = opts.checkpointPath ?? null;
|
|
9293
|
-
return async (
|
|
9859
|
+
return async (claimedTask, reporter) => {
|
|
9294
9860
|
if (!cachedCheckpoint) cachedCheckpoint = await ensureSnapshot({
|
|
9295
9861
|
config: opts.sandboxConfig?.snapshot,
|
|
9296
9862
|
onProgress: opts.onSnapshotProgress ?? ((m) => {
|
|
9297
9863
|
process.stderr.write(`[snapshot] ${m}\n`);
|
|
9298
9864
|
})
|
|
9299
9865
|
});
|
|
9300
|
-
return executePiTask(
|
|
9866
|
+
return executePiTask(claimedTask, reporter, {
|
|
9301
9867
|
...opts,
|
|
9302
9868
|
checkpointPath: cachedCheckpoint
|
|
9303
9869
|
});
|
|
@@ -9309,8 +9875,9 @@ function createPiTaskExecutor(opts) {
|
|
|
9309
9875
|
* a `TaskOutput` (failures surface as `status: 'failed'`); throws only on
|
|
9310
9876
|
* unrecoverable setup errors.
|
|
9311
9877
|
*/
|
|
9312
|
-
async function executePiTask(
|
|
9313
|
-
const
|
|
9878
|
+
async function executePiTask(claimedTask, reporter, opts) {
|
|
9879
|
+
const task = claimedTask.task;
|
|
9880
|
+
const attemptN = claimedTask.attemptN;
|
|
9314
9881
|
const startTime = Date.now();
|
|
9315
9882
|
const mountPath = opts.mountPath ?? process.cwd();
|
|
9316
9883
|
const checkpointPath = opts.checkpointPath ?? await ensureSnapshot({
|
|
@@ -9336,17 +9903,19 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9336
9903
|
extraAllowedHosts: opts.extraAllowedHosts,
|
|
9337
9904
|
sandboxConfig: opts.sandboxConfig
|
|
9338
9905
|
});
|
|
9339
|
-
const diaryId = task.
|
|
9906
|
+
const diaryId = task.diaryId ?? "";
|
|
9907
|
+
const taskTeamId = task.teamId ?? "";
|
|
9340
9908
|
let reporterOpen = false;
|
|
9341
9909
|
let session = null;
|
|
9342
|
-
const
|
|
9343
|
-
|
|
9344
|
-
|
|
9910
|
+
const finalUsage = emptyUsage(opts.provider, opts.model);
|
|
9911
|
+
const makeFailedOutput = (code, message, usage = finalUsage) => ({
|
|
9912
|
+
taskId: task.id,
|
|
9913
|
+
attemptN,
|
|
9345
9914
|
status: "failed",
|
|
9346
9915
|
output: null,
|
|
9347
|
-
|
|
9916
|
+
outputCid: null,
|
|
9348
9917
|
usage,
|
|
9349
|
-
|
|
9918
|
+
durationMs: Date.now() - startTime,
|
|
9350
9919
|
error: {
|
|
9351
9920
|
code,
|
|
9352
9921
|
message,
|
|
@@ -9367,8 +9936,8 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9367
9936
|
});
|
|
9368
9937
|
await emit("info", {
|
|
9369
9938
|
event: "execute_start",
|
|
9370
|
-
|
|
9371
|
-
|
|
9939
|
+
taskType: task.taskType,
|
|
9940
|
+
teamId: task.teamId,
|
|
9372
9941
|
provider: opts.provider,
|
|
9373
9942
|
model: opts.model
|
|
9374
9943
|
});
|
|
@@ -9398,8 +9967,11 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9398
9967
|
const moltnetTools = createMoltNetTools({
|
|
9399
9968
|
getAgent: () => moltnetAgent,
|
|
9400
9969
|
getDiaryId: () => diaryId,
|
|
9970
|
+
getTeamId: () => taskTeamId,
|
|
9401
9971
|
getSessionErrors: () => [],
|
|
9402
|
-
clearSessionErrors: () => {}
|
|
9972
|
+
clearSessionErrors: () => {},
|
|
9973
|
+
getHostCwd: () => mountPath,
|
|
9974
|
+
hostExecBaseEnv: new Set([...HOST_EXEC_DEFAULT_BASE_ENV, ...Object.keys(managed.credentials.agentEnv)])
|
|
9403
9975
|
});
|
|
9404
9976
|
const piAuthDir = join(homedir(), ".pi", "agent");
|
|
9405
9977
|
const modelHandle = getModel(opts.provider, opts.model);
|
|
@@ -9427,7 +9999,7 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9427
9999
|
let llmAbort = false;
|
|
9428
10000
|
let assistantText = "";
|
|
9429
10001
|
let reporterError = null;
|
|
9430
|
-
const usage =
|
|
10002
|
+
const usage = finalUsage;
|
|
9431
10003
|
const recordingPromise = [];
|
|
9432
10004
|
const track = (p) => {
|
|
9433
10005
|
recordingPromise.push(p.catch((err) => {
|
|
@@ -9457,12 +10029,12 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9457
10029
|
else if (event.type === "turn_end") {
|
|
9458
10030
|
const msg = event.message;
|
|
9459
10031
|
if (msg?.role === "assistant" && msg.usage) {
|
|
9460
|
-
usage.
|
|
9461
|
-
usage.
|
|
10032
|
+
usage.inputTokens += Math.max(0, msg.usage.input ?? 0);
|
|
10033
|
+
usage.outputTokens += Math.max(0, msg.usage.output ?? 0);
|
|
9462
10034
|
const cr = Math.max(0, msg.usage.cacheRead ?? 0);
|
|
9463
10035
|
const cw = Math.max(0, msg.usage.cacheWrite ?? 0);
|
|
9464
|
-
if (cr) usage.
|
|
9465
|
-
if (cw) usage.
|
|
10036
|
+
if (cr) usage.cacheReadTokens = (usage.cacheReadTokens ?? 0) + cr;
|
|
10037
|
+
if (cw) usage.cacheWriteTokens = (usage.cacheWriteTokens ?? 0) + cw;
|
|
9466
10038
|
}
|
|
9467
10039
|
track(emit("turn_end", { stop_reason: msg?.stopReason ?? "end_turn" }));
|
|
9468
10040
|
llmAbort = msg?.stopReason === "error";
|
|
@@ -9484,28 +10056,13 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9484
10056
|
}
|
|
9485
10057
|
await Promise.all(recordingPromise);
|
|
9486
10058
|
let parsedOutput = null;
|
|
10059
|
+
let parsedOutputCid = null;
|
|
9487
10060
|
let parseError = null;
|
|
9488
10061
|
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
|
-
}
|
|
10062
|
+
const parsed = await parseStructuredTaskOutput(assistantText, task.taskType);
|
|
10063
|
+
parsedOutput = parsed.output;
|
|
10064
|
+
parsedOutputCid = parsed.outputCid;
|
|
10065
|
+
parseError = parsed.error;
|
|
9509
10066
|
if (parseError) await emit("error", {
|
|
9510
10067
|
message: parseError.message,
|
|
9511
10068
|
phase: "output_validation"
|
|
@@ -9515,13 +10072,13 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9515
10072
|
const errorCode = runError?.code ?? parseError?.code ?? reporterError?.code ?? (llmAbort ? "llm_api_error" : void 0);
|
|
9516
10073
|
const errorMessage = runError?.message ?? parseError?.message ?? reporterError?.message ?? (llmAbort ? "LLM API error during turn" : void 0);
|
|
9517
10074
|
return {
|
|
9518
|
-
|
|
9519
|
-
|
|
10075
|
+
taskId: task.id,
|
|
10076
|
+
attemptN,
|
|
9520
10077
|
status,
|
|
9521
10078
|
output: parsedOutput,
|
|
9522
|
-
|
|
10079
|
+
outputCid: parsedOutputCid,
|
|
9523
10080
|
usage,
|
|
9524
|
-
|
|
10081
|
+
durationMs: Date.now() - startTime,
|
|
9525
10082
|
...errorCode && errorMessage ? { error: {
|
|
9526
10083
|
code: errorCode,
|
|
9527
10084
|
message: errorMessage,
|
|
@@ -9536,7 +10093,7 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9536
10093
|
} catch {}
|
|
9537
10094
|
if (reporterOpen) {
|
|
9538
10095
|
try {
|
|
9539
|
-
await reporter.finalize(
|
|
10096
|
+
await reporter.finalize(finalUsage);
|
|
9540
10097
|
} catch {}
|
|
9541
10098
|
try {
|
|
9542
10099
|
await reporter.close();
|
|
@@ -9547,8 +10104,8 @@ async function executePiTask(task, reporter, opts) {
|
|
|
9547
10104
|
}
|
|
9548
10105
|
function emptyUsage(provider, model) {
|
|
9549
10106
|
return {
|
|
9550
|
-
|
|
9551
|
-
|
|
10107
|
+
inputTokens: 0,
|
|
10108
|
+
outputTokens: 0,
|
|
9552
10109
|
provider,
|
|
9553
10110
|
model
|
|
9554
10111
|
};
|
|
@@ -9582,79 +10139,16 @@ function truncateForWire(value) {
|
|
|
9582
10139
|
};
|
|
9583
10140
|
}
|
|
9584
10141
|
}
|
|
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
10142
|
//#endregion
|
|
9636
10143
|
//#region src/index.ts
|
|
9637
10144
|
/**
|
|
9638
10145
|
* @themoltnet/pi-extension — MoltNet pi extension
|
|
9639
10146
|
*
|
|
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
|
|
9647
|
-
*
|
|
9648
|
-
* Usage:
|
|
9649
|
-
* pi -e @themoltnet/pi-extension
|
|
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
|
|
10147
|
+
* Runs pi coding-agent sessions inside a Gondolin VM with the agent's
|
|
10148
|
+
* MoltNet identity fully available inside the sandbox.
|
|
9653
10149
|
*
|
|
9654
|
-
*
|
|
9655
|
-
*
|
|
9656
|
-
* 2. sandbox.json in cwd (convention)
|
|
9657
|
-
* 3. Base only (git, gh, moltnet CLI, agent user)
|
|
10150
|
+
* See README.md for credential injection flow, tool split, sandbox.json
|
|
10151
|
+
* reference, and headless/programmatic usage.
|
|
9658
10152
|
*/
|
|
9659
10153
|
var GUEST_WORKSPACE = "/workspace";
|
|
9660
10154
|
function moltnetExtension(pi) {
|
|
@@ -9692,6 +10186,8 @@ function moltnetExtension(pi) {
|
|
|
9692
10186
|
let worktreePath = null;
|
|
9693
10187
|
let moltnetAgent = null;
|
|
9694
10188
|
let diaryId = null;
|
|
10189
|
+
let teamId = null;
|
|
10190
|
+
let hostExecBaseEnv = HOST_EXEC_DEFAULT_BASE_ENV;
|
|
9695
10191
|
async function ensureVm(ctx) {
|
|
9696
10192
|
if (vm) return vm;
|
|
9697
10193
|
if (vmStarting) return vmStarting;
|
|
@@ -9745,6 +10241,8 @@ function moltnetExtension(pi) {
|
|
|
9745
10241
|
activateAgentEnv(managed.credentials.agentEnv, mainRepo);
|
|
9746
10242
|
moltnetAgent = await connect({ configDir: managed.agentDir });
|
|
9747
10243
|
diaryId = managed.credentials.agentEnv.MOLTNET_DIARY_ID ?? null;
|
|
10244
|
+
teamId = managed.credentials.agentEnv.MOLTNET_TEAM_ID ?? null;
|
|
10245
|
+
hostExecBaseEnv = new Set([...HOST_EXEC_DEFAULT_BASE_ENV, ...Object.keys(managed.credentials.agentEnv)]);
|
|
9748
10246
|
vm = managed.vm;
|
|
9749
10247
|
const label = worktreePath ? `${mountPath} → ${GUEST_WORKSPACE}` : `${localCwd} → ${GUEST_WORKSPACE}`;
|
|
9750
10248
|
ctx?.ui.setStatus("sandbox", ctx.ui.theme.fg("accent", `Sandbox: running (${label})`));
|
|
@@ -9765,6 +10263,7 @@ function moltnetExtension(pi) {
|
|
|
9765
10263
|
vm = null;
|
|
9766
10264
|
vmStarting = null;
|
|
9767
10265
|
moltnetAgent = null;
|
|
10266
|
+
teamId = null;
|
|
9768
10267
|
}
|
|
9769
10268
|
});
|
|
9770
10269
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
@@ -9804,10 +10303,13 @@ function moltnetExtension(pi) {
|
|
|
9804
10303
|
const moltnetTools = createMoltNetTools({
|
|
9805
10304
|
getAgent: () => moltnetAgent,
|
|
9806
10305
|
getDiaryId: () => diaryId,
|
|
10306
|
+
getTeamId: () => teamId,
|
|
9807
10307
|
getSessionErrors: () => sessionErrors,
|
|
9808
10308
|
clearSessionErrors: () => {
|
|
9809
10309
|
sessionErrors.length = 0;
|
|
9810
|
-
}
|
|
10310
|
+
},
|
|
10311
|
+
getHostCwd: () => worktreePath ?? localCwd,
|
|
10312
|
+
hostExecBaseEnv
|
|
9811
10313
|
});
|
|
9812
10314
|
for (const tool of moltnetTools) pi.registerTool(tool);
|
|
9813
10315
|
const sessionStartTime = Date.now();
|
|
@@ -9913,4 +10415,4 @@ function moltnetExtension(pi) {
|
|
|
9913
10415
|
registerMoltnetReflectCommand(pi, state);
|
|
9914
10416
|
}
|
|
9915
10417
|
//#endregion
|
|
9916
|
-
export { activateAgentEnv, buildPiJudgeRecipeManifest, computePiJudgeRecipeCid, createGondolinBashOps, createGondolinEditOps, createGondolinReadOps, createGondolinWriteOps, createMoltNetTools, createPiTaskExecutor, moltnetExtension as default, ensureSnapshot, executePiTask, findMainWorktree, loadCredentials, resolvePiJudgeRecipeVersions, resumeVm, toGuestPath };
|
|
10418
|
+
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 };
|