@hachej/boring-agent 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{sandbox-handle-store-hK76cTjn.d.ts → agentPluginEvents-zyIvVjsA.d.ts} +28 -32
- package/dist/{chunk-F3CE5CNW.js → chunk-B5JECXMG.js} +5 -7
- package/dist/front/index.d.ts +23 -7
- package/dist/front/index.js +764 -421
- package/dist/front/styles.css +61 -0
- package/dist/{tool-ui-DSmWuqGe.d.ts → harness-DRrTn_5T.d.ts} +43 -24
- package/dist/server/index.d.ts +79 -10
- package/dist/server/index.js +243 -54
- package/dist/shared/index.d.ts +5 -3
- package/dist/shared/index.js +3 -1
- package/dist/tool-ui-DIFNGwYd.d.ts +20 -0
- package/docs/ACCESSIBILITY.md +55 -0
- package/docs/API.md +64 -0
- package/docs/CSP.md +40 -0
- package/docs/ERROR_CODES.md +54 -0
- package/docs/KNOWN_LIMITATIONS.md +100 -0
- package/docs/MIGRATION.md +50 -0
- package/docs/PERFORMANCE.md +68 -0
- package/docs/PLUGINS.md +108 -0
- package/docs/README.md +17 -0
- package/docs/RISKS-MULTI-TAB.md +46 -0
- package/docs/STYLING.md +71 -0
- package/docs/UI-SHADCN.md +56 -0
- package/docs/VERCEL_COSTS.md +103 -0
- package/docs/plans/AGENT_EVAL_FRAMEWORK.md +466 -0
- package/docs/plans/agent-package-spec.md +1777 -0
- package/docs/plans/harness-followup-capabilities.md +440 -0
- package/docs/plans/harness-tool-ui-capabilities.md +144 -0
- package/docs/plans/pi-followup-history-projection.md +229 -0
- package/docs/plans/pi-tools-migration.md +1061 -0
- package/docs/plans/reviews/pi-followup-history-codex-review.md +11 -0
- package/docs/plans/reviews/pi-followup-history-gpt-review.md +64 -0
- package/docs/plans/reviews/pi-followup-history-opus-review.md +43 -0
- package/docs/plans/reviews/pi-followup-history-xai-review.md +43 -0
- package/docs/plans/vercel-base-snapshot-template-plan.md +527 -0
- package/docs/plans/vercel-persistent-sandbox-adapter.md +553 -0
- package/docs/runtime.md +56 -0
- package/docs/tools.md +75 -0
- package/package.json +4 -3
package/dist/server/index.js
CHANGED
|
@@ -2034,12 +2034,12 @@ function fileRoutes(app, opts, done) {
|
|
|
2034
2034
|
import { createHash as createHash3 } from "crypto";
|
|
2035
2035
|
import { constants as constants2 } from "fs";
|
|
2036
2036
|
import { access as access2, chmod as chmod3, cp, mkdir as mkdir4, readdir as readdir2, readFile as readFile4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
|
|
2037
|
-
import { dirname as dirname5, join as join3, resolve as resolve3 } from "path";
|
|
2037
|
+
import { dirname as dirname5, isAbsolute as isAbsolute4, join as join3, relative as relative5, resolve as resolve3 } from "path";
|
|
2038
2038
|
import { fileURLToPath } from "url";
|
|
2039
2039
|
import { execFile } from "child_process";
|
|
2040
2040
|
import { promisify } from "util";
|
|
2041
2041
|
var execFileAsync = promisify(execFile);
|
|
2042
|
-
var PROVISIONING_VERSION =
|
|
2042
|
+
var PROVISIONING_VERSION = 2;
|
|
2043
2043
|
function toPath(value) {
|
|
2044
2044
|
return value instanceof URL ? fileURLToPath(value) : value;
|
|
2045
2045
|
}
|
|
@@ -2103,6 +2103,27 @@ async function fingerprint(contributions) {
|
|
|
2103
2103
|
hash.update(JSON.stringify(Object.fromEntries(Object.entries(spec.env ?? {}).map(([k, v]) => [k, String(v)]))));
|
|
2104
2104
|
if (await exists(projectFile)) await hashPath(dirname5(projectFile), hash);
|
|
2105
2105
|
}
|
|
2106
|
+
for (const spec of provisioning.nodePackages ?? []) {
|
|
2107
|
+
const packageRoot = toPath(spec.packageRoot);
|
|
2108
|
+
hash.update(`node-package:${spec.id}:${spec.packageName}:${packageRoot}
|
|
2109
|
+
`);
|
|
2110
|
+
const packageJson = join3(packageRoot, "package.json");
|
|
2111
|
+
const distDir = join3(packageRoot, "dist");
|
|
2112
|
+
const docsDir = join3(packageRoot, "docs");
|
|
2113
|
+
const skillsDir = join3(packageRoot, "skills");
|
|
2114
|
+
const referencesDir = join3(packageRoot, "references");
|
|
2115
|
+
const sourceDocsDir = join3(packageRoot, "src", "server", "docs");
|
|
2116
|
+
if (await exists(packageJson)) await hashPath(packageJson, hash);
|
|
2117
|
+
if (await exists(distDir)) await hashPath(distDir, hash);
|
|
2118
|
+
const templatesDir = join3(packageRoot, "templates");
|
|
2119
|
+
const publicDir = join3(packageRoot, "public");
|
|
2120
|
+
if (await exists(templatesDir)) await hashPath(templatesDir, hash);
|
|
2121
|
+
if (await exists(publicDir)) await hashPath(publicDir, hash);
|
|
2122
|
+
if (await exists(docsDir)) await hashPath(docsDir, hash);
|
|
2123
|
+
if (await exists(skillsDir)) await hashPath(skillsDir, hash);
|
|
2124
|
+
if (await exists(referencesDir)) await hashPath(referencesDir, hash);
|
|
2125
|
+
else if (!await exists(distDir) && await exists(sourceDocsDir)) await hashPath(sourceDocsDir, hash);
|
|
2126
|
+
}
|
|
2106
2127
|
}
|
|
2107
2128
|
return `sha256:${hash.digest("hex")}`;
|
|
2108
2129
|
}
|
|
@@ -2117,10 +2138,23 @@ function collectEnv(contributions) {
|
|
|
2117
2138
|
}
|
|
2118
2139
|
return env;
|
|
2119
2140
|
}
|
|
2141
|
+
function resolveTemplateTarget(workspaceRoot, target) {
|
|
2142
|
+
const rawTarget = target ?? ".";
|
|
2143
|
+
if (rawTarget.length === 0 || rawTarget.includes("\0") || rawTarget.includes("\\") || rawTarget.startsWith("/") || rawTarget.startsWith("//") || /^[A-Za-z]:[\\/]/.test(rawTarget) || rawTarget.split("/").includes("..")) {
|
|
2144
|
+
throw new Error(`Unsafe runtime template target: ${JSON.stringify(rawTarget)}. Template targets must be relative paths inside the workspace.`);
|
|
2145
|
+
}
|
|
2146
|
+
const root = resolve3(workspaceRoot);
|
|
2147
|
+
const resolved = resolve3(root, rawTarget);
|
|
2148
|
+
const rel = relative5(root, resolved);
|
|
2149
|
+
if (rel.startsWith("..") || isAbsolute4(rel)) {
|
|
2150
|
+
throw new Error(`Unsafe runtime template target: ${JSON.stringify(rawTarget)} resolves outside the workspace.`);
|
|
2151
|
+
}
|
|
2152
|
+
return resolved;
|
|
2153
|
+
}
|
|
2120
2154
|
async function seedTemplates(workspaceRoot, contributions) {
|
|
2121
2155
|
for (const { provisioning } of contributions) {
|
|
2122
2156
|
for (const template of provisioning.templateDirs ?? []) {
|
|
2123
|
-
await cp(toPath(template.path),
|
|
2157
|
+
await cp(toPath(template.path), resolveTemplateTarget(workspaceRoot, template.target), {
|
|
2124
2158
|
recursive: true,
|
|
2125
2159
|
force: false,
|
|
2126
2160
|
errorOnExist: false
|
|
@@ -2128,6 +2162,45 @@ async function seedTemplates(workspaceRoot, contributions) {
|
|
|
2128
2162
|
}
|
|
2129
2163
|
}
|
|
2130
2164
|
}
|
|
2165
|
+
function nodePackageTarget(workspaceRoot, packageName) {
|
|
2166
|
+
const parts = packageName.split("/").filter(Boolean);
|
|
2167
|
+
if (parts.length === 0 || parts.some((part) => part === "." || part === "..")) {
|
|
2168
|
+
throw new Error(`Invalid node package name: ${packageName}`);
|
|
2169
|
+
}
|
|
2170
|
+
return join3(workspaceRoot, "node_modules", ...parts);
|
|
2171
|
+
}
|
|
2172
|
+
async function copyIfExists(source, target) {
|
|
2173
|
+
if (!await exists(source)) return false;
|
|
2174
|
+
await cp(source, target, {
|
|
2175
|
+
recursive: true,
|
|
2176
|
+
force: true,
|
|
2177
|
+
errorOnExist: false
|
|
2178
|
+
});
|
|
2179
|
+
return true;
|
|
2180
|
+
}
|
|
2181
|
+
async function ensureNodePackages(workspaceRoot, specs) {
|
|
2182
|
+
for (const spec of specs) {
|
|
2183
|
+
const packageRoot = toPath(spec.packageRoot);
|
|
2184
|
+
const target = nodePackageTarget(workspaceRoot, spec.packageName);
|
|
2185
|
+
await mkdir4(target, { recursive: true });
|
|
2186
|
+
const copiedPackageJson = await copyIfExists(join3(packageRoot, "package.json"), join3(target, "package.json"));
|
|
2187
|
+
if (!copiedPackageJson) {
|
|
2188
|
+
throw new Error(`Node package provisioning source is missing package.json: ${packageRoot}`);
|
|
2189
|
+
}
|
|
2190
|
+
await copyIfExists(join3(packageRoot, "dist"), join3(target, "dist"));
|
|
2191
|
+
await copyIfExists(join3(packageRoot, "templates"), join3(target, "templates"));
|
|
2192
|
+
await copyIfExists(join3(packageRoot, "public"), join3(target, "public"));
|
|
2193
|
+
if (!await exists(join3(target, "dist", "docs", "plugins.md"))) {
|
|
2194
|
+
await copyIfExists(join3(packageRoot, "src", "server", "docs"), join3(target, "dist", "docs"));
|
|
2195
|
+
}
|
|
2196
|
+
if (!await copyIfExists(join3(packageRoot, "docs"), join3(target, "docs"))) {
|
|
2197
|
+
await copyIfExists(join3(packageRoot, "src", "server", "docs"), join3(target, "docs"));
|
|
2198
|
+
}
|
|
2199
|
+
await copyIfExists(join3(packageRoot, "skills"), join3(target, "skills"));
|
|
2200
|
+
await copyIfExists(join3(packageRoot, "references"), join3(target, "references"));
|
|
2201
|
+
await copyIfExists(join3(packageRoot, "src", "globals.css"), join3(target, "src", "globals.css"));
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2131
2204
|
async function ensurePython(workspaceRoot, specs) {
|
|
2132
2205
|
if (specs.length === 0) return;
|
|
2133
2206
|
const venvPython = join3(workspaceRoot, ".venv", "bin", "python");
|
|
@@ -2164,6 +2237,11 @@ function assertEnvKey(key) {
|
|
|
2164
2237
|
async function isRuntimeMaterialized(workspaceRoot, contributions) {
|
|
2165
2238
|
const hasPython = contributions.some(({ provisioning }) => (provisioning.python ?? []).length > 0);
|
|
2166
2239
|
if (hasPython && !await exists(join3(workspaceRoot, ".venv", "bin", "python"))) return false;
|
|
2240
|
+
for (const { provisioning } of contributions) {
|
|
2241
|
+
for (const spec of provisioning.nodePackages ?? []) {
|
|
2242
|
+
if (!await exists(join3(nodePackageTarget(workspaceRoot, spec.packageName), "package.json"))) return false;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2167
2245
|
return true;
|
|
2168
2246
|
}
|
|
2169
2247
|
async function writeShims(workspaceRoot, env) {
|
|
@@ -2232,6 +2310,7 @@ async function provisionRuntimeWorkspace({
|
|
|
2232
2310
|
}
|
|
2233
2311
|
}
|
|
2234
2312
|
await seedTemplates(workspaceRoot, active);
|
|
2313
|
+
await ensureNodePackages(workspaceRoot, active.flatMap(({ provisioning }) => provisioning.nodePackages ?? []));
|
|
2235
2314
|
await ensurePython(workspaceRoot, active.flatMap(({ provisioning }) => provisioning.python ?? []));
|
|
2236
2315
|
const actualBinDir = await writeShims(workspaceRoot, env);
|
|
2237
2316
|
await mkdir4(dirname5(markerPath), { recursive: true });
|
|
@@ -2649,8 +2728,10 @@ function createServerFileSearch(workspace, sandbox) {
|
|
|
2649
2728
|
const command = [
|
|
2650
2729
|
"find .",
|
|
2651
2730
|
"-maxdepth 10",
|
|
2731
|
+
"-path './.boring-agent' -prune -o",
|
|
2652
2732
|
buildFindArgs(glob),
|
|
2653
2733
|
"-type f",
|
|
2734
|
+
"-print",
|
|
2654
2735
|
`| head -n ${safeLimit}`
|
|
2655
2736
|
].join(" ");
|
|
2656
2737
|
const { stdout, exitCode } = await sandbox.exec(command, {
|
|
@@ -3274,7 +3355,6 @@ function resolveMode(mode = autoDetectMode()) {
|
|
|
3274
3355
|
|
|
3275
3356
|
// src/server/createAgentApp.ts
|
|
3276
3357
|
import Fastify from "fastify";
|
|
3277
|
-
import { basename as basename2 } from "path";
|
|
3278
3358
|
|
|
3279
3359
|
// src/server/harness/pi-coding-agent/createHarness.ts
|
|
3280
3360
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
@@ -3287,7 +3367,8 @@ import {
|
|
|
3287
3367
|
ModelRegistry,
|
|
3288
3368
|
DefaultResourceLoader,
|
|
3289
3369
|
SettingsManager as SettingsManager2,
|
|
3290
|
-
getAgentDir as getAgentDir2
|
|
3370
|
+
getAgentDir as getAgentDir2,
|
|
3371
|
+
loadSkills
|
|
3291
3372
|
} from "@mariozechner/pi-coding-agent";
|
|
3292
3373
|
|
|
3293
3374
|
// src/server/harness/pi-coding-agent/tool-adapter.ts
|
|
@@ -4216,6 +4297,17 @@ var WORKSPACE_PATHS_GUIDELINE = [
|
|
|
4216
4297
|
function composeSystemPromptAppend(hostAppend) {
|
|
4217
4298
|
return [WORKSPACE_PATHS_GUIDELINE, hostAppend?.trim()].filter(Boolean).join("\n\n");
|
|
4218
4299
|
}
|
|
4300
|
+
function buildDynamicPromptExtension(source) {
|
|
4301
|
+
return (pi) => {
|
|
4302
|
+
pi.on("before_agent_start", async (event) => {
|
|
4303
|
+
const extra = (await source())?.trim();
|
|
4304
|
+
if (!extra) return;
|
|
4305
|
+
return { systemPrompt: `${event.systemPrompt}
|
|
4306
|
+
|
|
4307
|
+
${extra}` };
|
|
4308
|
+
});
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4219
4311
|
function extractUserMessageText(message) {
|
|
4220
4312
|
const record = message;
|
|
4221
4313
|
if (record?.role !== "user") return "";
|
|
@@ -4341,6 +4433,30 @@ function createPiCodingAgentHarness(opts) {
|
|
|
4341
4433
|
sessionDir: opts.sessionDir
|
|
4342
4434
|
});
|
|
4343
4435
|
const piSessions = /* @__PURE__ */ new Map();
|
|
4436
|
+
const effectiveSkillPaths = [];
|
|
4437
|
+
const effectivePackages = [];
|
|
4438
|
+
const effectiveExtensionPaths = [];
|
|
4439
|
+
const refreshEffectiveResources = () => {
|
|
4440
|
+
const dynamic = opts.pi?.getHotReloadableResources?.() ?? {};
|
|
4441
|
+
effectiveSkillPaths.splice(
|
|
4442
|
+
0,
|
|
4443
|
+
effectiveSkillPaths.length,
|
|
4444
|
+
...opts.pi?.additionalSkillPaths ?? [],
|
|
4445
|
+
...dynamic.additionalSkillPaths ?? []
|
|
4446
|
+
);
|
|
4447
|
+
effectivePackages.splice(
|
|
4448
|
+
0,
|
|
4449
|
+
effectivePackages.length,
|
|
4450
|
+
...mergePiPackageSources(opts.pi?.packages ?? [], dynamic.packages ?? [])
|
|
4451
|
+
);
|
|
4452
|
+
effectiveExtensionPaths.splice(
|
|
4453
|
+
0,
|
|
4454
|
+
effectiveExtensionPaths.length,
|
|
4455
|
+
...opts.pi?.extensionPaths ?? [],
|
|
4456
|
+
...dynamic.extensionPaths ?? []
|
|
4457
|
+
);
|
|
4458
|
+
};
|
|
4459
|
+
refreshEffectiveResources();
|
|
4344
4460
|
const scheduleSessionTitle = createSessionTitleScheduler({
|
|
4345
4461
|
loadSession: (sessionId) => sessionStore.load({ workspaceId: "default" }, sessionId),
|
|
4346
4462
|
writeTitle: (sessionId, title) => {
|
|
@@ -4373,23 +4489,44 @@ function createPiCodingAgentHarness(opts) {
|
|
|
4373
4489
|
}
|
|
4374
4490
|
const resolvedModel = resolveRequestedModel(modelRegistry, input);
|
|
4375
4491
|
const model = resolvedModel ?? resolveDefaultModel(modelRegistry);
|
|
4492
|
+
refreshEffectiveResources();
|
|
4376
4493
|
const composedSystemPromptAppend = composeSystemPromptAppend(opts.systemPromptAppend);
|
|
4494
|
+
const dynamicPromptExtension = opts.systemPromptDynamic ? buildDynamicPromptExtension(opts.systemPromptDynamic) : void 0;
|
|
4377
4495
|
const agentDir = getAgentDir2();
|
|
4378
|
-
const
|
|
4379
|
-
|
|
4496
|
+
const extensionFactories = [
|
|
4497
|
+
...dynamicPromptExtension ? [dynamicPromptExtension] : [],
|
|
4498
|
+
...opts.pi?.extensionFactories ?? []
|
|
4499
|
+
];
|
|
4380
4500
|
const settingsManager = createResourceSettingsManager(
|
|
4381
4501
|
ctx.workdir,
|
|
4382
4502
|
agentDir,
|
|
4383
|
-
|
|
4503
|
+
effectivePackages
|
|
4384
4504
|
);
|
|
4385
4505
|
const resourceLoader = new DefaultResourceLoader({
|
|
4386
4506
|
cwd: ctx.workdir,
|
|
4387
4507
|
agentDir,
|
|
4388
4508
|
settingsManager,
|
|
4389
4509
|
appendSystemPromptOverride: (base) => [...base, composedSystemPromptAppend],
|
|
4390
|
-
...
|
|
4391
|
-
...
|
|
4392
|
-
...
|
|
4510
|
+
...effectiveExtensionPaths.length ? { additionalExtensionPaths: effectiveExtensionPaths } : {},
|
|
4511
|
+
...extensionFactories.length ? { extensionFactories } : {},
|
|
4512
|
+
...opts.pi?.noContextFiles ? { noContextFiles: true } : {},
|
|
4513
|
+
...opts.pi?.noSkills ? { noSkills: true } : {},
|
|
4514
|
+
...effectiveSkillPaths.length ? { additionalSkillPaths: effectiveSkillPaths } : {},
|
|
4515
|
+
// skillsOverride REPLACES Pi's resolved skill set, which includes
|
|
4516
|
+
// skills contributed by host-declared pi packages (e.g.
|
|
4517
|
+
// @hachej/boring-pi → boring-plugin-authoring). Only trigger it for
|
|
4518
|
+
// the explicit `noSkills` opt-out, where the host wants a clean slate.
|
|
4519
|
+
// Passing additionalSkillPaths is not, by itself, a request to throw
|
|
4520
|
+
// away package skills — those should keep flowing through Pi's loader
|
|
4521
|
+
// and merge with the additional paths.
|
|
4522
|
+
...opts.pi?.noSkills ? {
|
|
4523
|
+
skillsOverride: () => loadSkills({
|
|
4524
|
+
cwd: ctx.workdir,
|
|
4525
|
+
agentDir,
|
|
4526
|
+
skillPaths: effectiveSkillPaths,
|
|
4527
|
+
includeDefaults: false
|
|
4528
|
+
})
|
|
4529
|
+
} : {}
|
|
4393
4530
|
});
|
|
4394
4531
|
await resourceLoader?.reload();
|
|
4395
4532
|
const { session: piSession } = await createAgentSession({
|
|
@@ -4414,6 +4551,13 @@ function createPiCodingAgentHarness(opts) {
|
|
|
4414
4551
|
piSessions.set(sessionId, handle);
|
|
4415
4552
|
return handle;
|
|
4416
4553
|
}
|
|
4554
|
+
async function reloadPiSession(sessionId) {
|
|
4555
|
+
const handle = piSessions.get(sessionId);
|
|
4556
|
+
if (!handle) return false;
|
|
4557
|
+
refreshEffectiveResources();
|
|
4558
|
+
await handle.piSession.reload();
|
|
4559
|
+
return true;
|
|
4560
|
+
}
|
|
4417
4561
|
function disposePiSession(sessionId) {
|
|
4418
4562
|
const handle = piSessions.get(sessionId);
|
|
4419
4563
|
if (!handle) return;
|
|
@@ -4526,6 +4670,7 @@ function createPiCodingAgentHarness(opts) {
|
|
|
4526
4670
|
getSystemPrompt(sessionId) {
|
|
4527
4671
|
return piSessions.get(sessionId)?.piSession.systemPrompt;
|
|
4528
4672
|
},
|
|
4673
|
+
reloadSession: reloadPiSession,
|
|
4529
4674
|
async *sendMessage(input, ctx) {
|
|
4530
4675
|
const { piSession } = await getOrCreatePiSession(
|
|
4531
4676
|
input.sessionId,
|
|
@@ -4926,7 +5071,7 @@ ${attachmentNotes.join("\n")}` : message,
|
|
|
4926
5071
|
|
|
4927
5072
|
// src/server/harness/pi-coding-agent/pluginLoader.ts
|
|
4928
5073
|
import { readdir as readdir5, stat as stat5, readFile as readFile7 } from "fs/promises";
|
|
4929
|
-
import { join as join7, extname as extname3, resolve as resolve4, sep as sep3, relative as
|
|
5074
|
+
import { join as join7, extname as extname3, resolve as resolve4, sep as sep3, relative as relative6 } from "path";
|
|
4930
5075
|
import { homedir as homedir4 } from "os";
|
|
4931
5076
|
import { pathToFileURL } from "url";
|
|
4932
5077
|
var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs"]);
|
|
@@ -5001,7 +5146,7 @@ async function loadNpmPlugin(pkgDir, importFn) {
|
|
|
5001
5146
|
if (resolvedMain !== resolvedPkgDir && !resolvedMain.startsWith(resolvedPkgDir + sep3)) {
|
|
5002
5147
|
return [];
|
|
5003
5148
|
}
|
|
5004
|
-
const relPath =
|
|
5149
|
+
const relPath = relative6(resolvedPkgDir, resolvedMain);
|
|
5005
5150
|
if (relPath.startsWith("..")) {
|
|
5006
5151
|
return [];
|
|
5007
5152
|
}
|
|
@@ -5086,7 +5231,7 @@ import {
|
|
|
5086
5231
|
// src/server/tools/operations/bound.ts
|
|
5087
5232
|
import { constants as constants3 } from "fs";
|
|
5088
5233
|
import { access as access3, lstat as lstat3, mkdir as mkdir10, readFile as readFile8, readdir as readdir6, readlink, realpath as realpath2, stat as stat6, writeFile as writeFile8 } from "fs/promises";
|
|
5089
|
-
import { dirname as dirname7, isAbsolute as
|
|
5234
|
+
import { dirname as dirname7, isAbsolute as isAbsolute5, relative as relative7, resolve as resolve5 } from "path";
|
|
5090
5235
|
function toPosixPath(value) {
|
|
5091
5236
|
return value.split("\\").join("/");
|
|
5092
5237
|
}
|
|
@@ -5131,8 +5276,8 @@ function matchesGlob(relativePath, pattern) {
|
|
|
5131
5276
|
}
|
|
5132
5277
|
function shouldSkipDir(relativePath, ignore) {
|
|
5133
5278
|
const normalizedRel = toPosixPath(relativePath);
|
|
5134
|
-
const
|
|
5135
|
-
if (
|
|
5279
|
+
const basename3 = normalizedRel.split("/").at(-1) ?? normalizedRel;
|
|
5280
|
+
if (basename3 === ".git" || basename3 === "node_modules") return true;
|
|
5136
5281
|
return ignore.some((pattern) => {
|
|
5137
5282
|
return matchesGlob(normalizedRel, pattern) || matchesGlob(`${normalizedRel}/`, pattern);
|
|
5138
5283
|
});
|
|
@@ -5143,7 +5288,7 @@ async function walkMatches(root, current, pattern, ignore, limit, out) {
|
|
|
5143
5288
|
for (const entry of entries) {
|
|
5144
5289
|
if (out.length >= limit) return;
|
|
5145
5290
|
const absolutePath = resolve5(current, entry.name);
|
|
5146
|
-
const relativePath = toPosixPath(
|
|
5291
|
+
const relativePath = toPosixPath(relative7(root, absolutePath));
|
|
5147
5292
|
if (entry.isDirectory() && shouldSkipDir(relativePath, ignore)) continue;
|
|
5148
5293
|
if (matchesGlob(relativePath, pattern)) {
|
|
5149
5294
|
out.push(absolutePath);
|
|
@@ -5175,8 +5320,8 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
|
|
|
5175
5320
|
const resolvedTarget = resolve5(dirname7(absPath), target);
|
|
5176
5321
|
const nearestAncestor = await findNearestExistingAncestor(resolvedTarget);
|
|
5177
5322
|
const realAncestor = await realpath2(nearestAncestor);
|
|
5178
|
-
const rel2 =
|
|
5179
|
-
if (rel2.startsWith("..") ||
|
|
5323
|
+
const rel2 = relative7(realRoot, realAncestor);
|
|
5324
|
+
if (rel2.startsWith("..") || isAbsolute5(rel2)) {
|
|
5180
5325
|
throw new Error(`path "${absPath}" is outside workspace`);
|
|
5181
5326
|
}
|
|
5182
5327
|
return;
|
|
@@ -5196,16 +5341,16 @@ async function assertWithinWorkspace(workspaceRoot, absPath) {
|
|
|
5196
5341
|
if (code === "ENOENT") {
|
|
5197
5342
|
const nearestAncestor = await findNearestExistingAncestor(dirname7(absPath));
|
|
5198
5343
|
const realAncestor = await realpath2(nearestAncestor);
|
|
5199
|
-
const rel2 =
|
|
5200
|
-
if (rel2.startsWith("..") ||
|
|
5344
|
+
const rel2 = relative7(realRoot, realAncestor);
|
|
5345
|
+
if (rel2.startsWith("..") || isAbsolute5(rel2)) {
|
|
5201
5346
|
throw new Error(`path "${absPath}" is outside workspace`);
|
|
5202
5347
|
}
|
|
5203
5348
|
return;
|
|
5204
5349
|
}
|
|
5205
5350
|
throw err;
|
|
5206
5351
|
}
|
|
5207
|
-
const rel =
|
|
5208
|
-
if (rel.startsWith("..") ||
|
|
5352
|
+
const rel = relative7(realRoot, realCandidate);
|
|
5353
|
+
if (rel.startsWith("..") || isAbsolute5(rel)) {
|
|
5209
5354
|
throw new Error(`path "${absPath}" is outside workspace`);
|
|
5210
5355
|
}
|
|
5211
5356
|
}
|
|
@@ -5296,7 +5441,7 @@ function boundFs(workspaceRoot) {
|
|
|
5296
5441
|
}
|
|
5297
5442
|
|
|
5298
5443
|
// src/server/tools/operations/vercel.ts
|
|
5299
|
-
import { isAbsolute as
|
|
5444
|
+
import { isAbsolute as isAbsolute6, relative as relative8 } from "path";
|
|
5300
5445
|
function rootAliases(workspace) {
|
|
5301
5446
|
const aliases = [workspace.root];
|
|
5302
5447
|
if (workspace.root === VERCEL_SANDBOX_WORKSPACE_ROOT) aliases.push(VERCEL_SANDBOX_REMOTE_ROOT);
|
|
@@ -5304,11 +5449,11 @@ function rootAliases(workspace) {
|
|
|
5304
5449
|
return aliases;
|
|
5305
5450
|
}
|
|
5306
5451
|
function isOutsideWorkspaceRel(rel) {
|
|
5307
|
-
return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") ||
|
|
5452
|
+
return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute6(rel);
|
|
5308
5453
|
}
|
|
5309
5454
|
function toRelPath(workspace, absolutePath) {
|
|
5310
5455
|
for (const root of rootAliases(workspace)) {
|
|
5311
|
-
const rel =
|
|
5456
|
+
const rel = relative8(root, absolutePath);
|
|
5312
5457
|
if (!isOutsideWorkspaceRel(rel)) return rel;
|
|
5313
5458
|
}
|
|
5314
5459
|
const skillMarker = "/.agents/skills/";
|
|
@@ -5491,7 +5636,7 @@ import {
|
|
|
5491
5636
|
truncateHead,
|
|
5492
5637
|
truncateLine
|
|
5493
5638
|
} from "@mariozechner/pi-coding-agent";
|
|
5494
|
-
import { resolve as resolve6, relative as
|
|
5639
|
+
import { resolve as resolve6, relative as relative9 } from "path";
|
|
5495
5640
|
|
|
5496
5641
|
// src/server/catalog/tools/_shared.ts
|
|
5497
5642
|
function makeError(message) {
|
|
@@ -5644,7 +5789,7 @@ function vercelGrepTool(sandbox, workspaceRoot) {
|
|
|
5644
5789
|
}
|
|
5645
5790
|
if (workspaceRoot && typeof params.path === "string" && params.path.length > 0) {
|
|
5646
5791
|
const resolved = resolve6(workspaceRoot, params.path);
|
|
5647
|
-
const rel =
|
|
5792
|
+
const rel = relative9(workspaceRoot, resolved);
|
|
5648
5793
|
if (rel.startsWith("..") || rel.startsWith("/")) {
|
|
5649
5794
|
return makeError(`path "${params.path}" is outside workspace`);
|
|
5650
5795
|
}
|
|
@@ -5804,8 +5949,7 @@ function createExecuteIsolatedCodeTool(sandbox) {
|
|
|
5804
5949
|
language: { type: "string", enum: ["python", "shell"] },
|
|
5805
5950
|
image: { type: "string" },
|
|
5806
5951
|
packages: { type: "array", items: { type: "string" } },
|
|
5807
|
-
sandboxId: { type: "string" }
|
|
5808
|
-
vmSize: { type: "string", enum: ["xxs", "xs", "s", "m", "l"] }
|
|
5952
|
+
sandboxId: { type: "string" }
|
|
5809
5953
|
},
|
|
5810
5954
|
required: ["code", "language"],
|
|
5811
5955
|
additionalProperties: false
|
|
@@ -5831,8 +5975,7 @@ function createExecuteIsolatedCodeTool(sandbox) {
|
|
|
5831
5975
|
language,
|
|
5832
5976
|
image: typeof input.image === "string" ? input.image : void 0,
|
|
5833
5977
|
packages: Array.isArray(input.packages) ? input.packages.filter((v) => typeof v === "string") : void 0,
|
|
5834
|
-
sandboxId: typeof input.sandboxId === "string" ? input.sandboxId : void 0
|
|
5835
|
-
vmSize: input.vmSize === "xxs" || input.vmSize === "xs" || input.vmSize === "s" || input.vmSize === "m" || input.vmSize === "l" ? input.vmSize : void 0
|
|
5978
|
+
sandboxId: typeof input.sandboxId === "string" ? input.sandboxId : void 0
|
|
5836
5979
|
});
|
|
5837
5980
|
return {
|
|
5838
5981
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
@@ -6751,7 +6894,7 @@ function modelsRoutes(app, _opts, done) {
|
|
|
6751
6894
|
import {
|
|
6752
6895
|
DefaultPackageManager,
|
|
6753
6896
|
getAgentDir as getAgentDir3,
|
|
6754
|
-
loadSkills
|
|
6897
|
+
loadSkills as loadSkills2
|
|
6755
6898
|
} from "@mariozechner/pi-coding-agent";
|
|
6756
6899
|
var CACHE_TTL_MS2 = 3e4;
|
|
6757
6900
|
function skillsRoutes(app, opts, done) {
|
|
@@ -6786,7 +6929,7 @@ function skillsRoutes(app, opts, done) {
|
|
|
6786
6929
|
const resolved = await packageManager.resolve();
|
|
6787
6930
|
return resolved.skills.filter((resource) => resource.enabled).map((resource) => resource.path);
|
|
6788
6931
|
})();
|
|
6789
|
-
const result =
|
|
6932
|
+
const result = loadSkills2({
|
|
6790
6933
|
cwd: workspaceRoot,
|
|
6791
6934
|
agentDir,
|
|
6792
6935
|
skillPaths: [...packageSkillPaths, ...additionalSkillPaths ?? []],
|
|
@@ -7329,6 +7472,33 @@ data: ${JSON.stringify(event)}
|
|
|
7329
7472
|
done();
|
|
7330
7473
|
}
|
|
7331
7474
|
|
|
7475
|
+
// src/server/http/routes/reload.ts
|
|
7476
|
+
function reloadRoutes(app, opts, done) {
|
|
7477
|
+
app.post("/api/v1/agent/reload", async (request, reply) => {
|
|
7478
|
+
if (!opts.harness.reloadSession) {
|
|
7479
|
+
return reply.status(501).send({ ok: false, error: "Agent harness does not support reload" });
|
|
7480
|
+
}
|
|
7481
|
+
const sessionId = request.body?.sessionId || opts.defaultSessionId;
|
|
7482
|
+
try {
|
|
7483
|
+
const hookResult = await opts.beforeReload?.();
|
|
7484
|
+
const reloaded = await opts.harness.reloadSession(sessionId);
|
|
7485
|
+
const restart_warnings = hookResult?.restart_warnings;
|
|
7486
|
+
const diagnostics = hookResult?.diagnostics;
|
|
7487
|
+
return {
|
|
7488
|
+
ok: true,
|
|
7489
|
+
sessionId,
|
|
7490
|
+
reloaded,
|
|
7491
|
+
...restart_warnings && restart_warnings.length > 0 ? { restart_warnings } : {},
|
|
7492
|
+
...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
|
|
7493
|
+
};
|
|
7494
|
+
} catch (error) {
|
|
7495
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7496
|
+
return reply.status(422).send({ ok: false, error: message });
|
|
7497
|
+
}
|
|
7498
|
+
});
|
|
7499
|
+
done();
|
|
7500
|
+
}
|
|
7501
|
+
|
|
7332
7502
|
// src/server/http/routes/search.ts
|
|
7333
7503
|
var MAX_GLOB_LENGTH = 256;
|
|
7334
7504
|
var DEFAULT_LIMIT3 = 500;
|
|
@@ -7474,13 +7644,21 @@ async function createAgentApp(opts = {}) {
|
|
|
7474
7644
|
...opts.extraTools ?? [],
|
|
7475
7645
|
...pluginTools
|
|
7476
7646
|
];
|
|
7477
|
-
const
|
|
7647
|
+
const harnessFactory = opts.harnessFactory ?? ((input) => createPiCodingAgentHarness({
|
|
7648
|
+
...input,
|
|
7649
|
+
pi: {
|
|
7650
|
+
noContextFiles: true,
|
|
7651
|
+
noSkills: true,
|
|
7652
|
+
...opts.pi
|
|
7653
|
+
}
|
|
7654
|
+
}));
|
|
7655
|
+
const harness = await harnessFactory({
|
|
7478
7656
|
tools,
|
|
7479
7657
|
cwd: workspaceRoot,
|
|
7480
7658
|
sessionNamespace: opts.sessionNamespace,
|
|
7481
7659
|
sessionDir: opts.sessionDir,
|
|
7482
7660
|
systemPromptAppend: opts.systemPromptAppend,
|
|
7483
|
-
|
|
7661
|
+
systemPromptDynamic: opts.systemPromptDynamic
|
|
7484
7662
|
});
|
|
7485
7663
|
const sessionChangesTracker = new InMemorySessionChangesTracker();
|
|
7486
7664
|
const readyTracker = new ReadyStatusTracker({
|
|
@@ -7519,10 +7697,13 @@ async function createAgentApp(opts = {}) {
|
|
|
7519
7697
|
await app.register(modelsRoutes);
|
|
7520
7698
|
await app.register(skillsRoutes, {
|
|
7521
7699
|
workspaceRoot,
|
|
7522
|
-
additionalSkillPaths: opts.
|
|
7700
|
+
additionalSkillPaths: opts.pi?.additionalSkillPaths,
|
|
7701
|
+
piPackages: opts.pi?.packages,
|
|
7702
|
+
noSkills: opts.pi?.noSkills
|
|
7523
7703
|
});
|
|
7524
7704
|
await app.register(sessionChangesRoutes, { tracker: sessionChangesTracker });
|
|
7525
7705
|
await app.register(catalogRoutes, { tools });
|
|
7706
|
+
await app.register(reloadRoutes, { harness, defaultSessionId: sessionId, beforeReload: opts.beforeReload });
|
|
7526
7707
|
await app.register(readyStatusRoutes, { tracker: readyTracker });
|
|
7527
7708
|
return app;
|
|
7528
7709
|
}
|
|
@@ -7552,7 +7733,7 @@ function applyCspHeaders(response, opts = {}) {
|
|
|
7552
7733
|
}
|
|
7553
7734
|
|
|
7554
7735
|
// src/server/registerAgentRoutes.ts
|
|
7555
|
-
import { basename as
|
|
7736
|
+
import { basename as basename2 } from "path";
|
|
7556
7737
|
import { AuthStorage as AuthStorage3, ModelRegistry as ModelRegistry3 } from "@mariozechner/pi-coding-agent";
|
|
7557
7738
|
|
|
7558
7739
|
// src/server/catalog/mergeTools.ts
|
|
@@ -7699,7 +7880,7 @@ var DEFAULT_WORKSPACE_ID3 = "default";
|
|
|
7699
7880
|
var STANDARD_AGENT_TOOL_NAMES = ["bash", "read", "write", "edit", "find", "grep", "ls"];
|
|
7700
7881
|
var VERCEL_BINDING_HEALTHCHECK_INTERVAL_MS = 15e3;
|
|
7701
7882
|
function pluginNameFromPath(path4) {
|
|
7702
|
-
const fileName =
|
|
7883
|
+
const fileName = basename2(path4);
|
|
7703
7884
|
if (fileName.endsWith(".mjs")) return fileName.slice(0, -4);
|
|
7704
7885
|
if (fileName.endsWith(".js")) return fileName.slice(0, -3);
|
|
7705
7886
|
return fileName;
|
|
@@ -7758,7 +7939,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
7758
7939
|
app.addHook("onClose", async () => {
|
|
7759
7940
|
await modeAdapter.dispose?.();
|
|
7760
7941
|
});
|
|
7761
|
-
const requestScopedRuntime = typeof opts.getWorkspaceId === "function" || typeof opts.getWorkspaceRoot === "function" || typeof opts.getTemplatePath === "function" || typeof opts.
|
|
7942
|
+
const requestScopedRuntime = typeof opts.getWorkspaceId === "function" || typeof opts.getWorkspaceRoot === "function" || typeof opts.getTemplatePath === "function" || typeof opts.getPi === "function" || typeof opts.getSessionNamespace === "function";
|
|
7762
7943
|
const sessionChangesTracker = new InMemorySessionChangesTracker();
|
|
7763
7944
|
const runtimeBindings = /* @__PURE__ */ new Map();
|
|
7764
7945
|
const MAX_RUNTIME_BINDINGS = 256;
|
|
@@ -7772,27 +7953,27 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
7772
7953
|
async function resolveRuntimeScope(workspaceId, request) {
|
|
7773
7954
|
const root = request && opts.getWorkspaceRoot ? await opts.getWorkspaceRoot(workspaceId, request) : workspaceRoot;
|
|
7774
7955
|
const scopedTemplatePath = opts.getTemplatePath ? await opts.getTemplatePath({ workspaceId, workspaceRoot: root, request }) : templatePath;
|
|
7775
|
-
const
|
|
7956
|
+
const pi = opts.getPi ? await opts.getPi({ workspaceId, workspaceRoot: root, request }) : opts.pi;
|
|
7776
7957
|
const sessionNamespace = normalizeSessionNamespace(opts.getSessionNamespace ? await opts.getSessionNamespace({ workspaceId, workspaceRoot: root, request }) : opts.sessionNamespace);
|
|
7777
7958
|
return {
|
|
7778
7959
|
root,
|
|
7779
7960
|
templatePath: scopedTemplatePath,
|
|
7780
|
-
|
|
7961
|
+
pi,
|
|
7781
7962
|
sessionNamespace,
|
|
7782
7963
|
key: JSON.stringify([
|
|
7783
7964
|
resolvedMode,
|
|
7784
7965
|
workspaceId,
|
|
7785
7966
|
root,
|
|
7786
7967
|
scopedTemplatePath ?? null,
|
|
7787
|
-
|
|
7968
|
+
pi ?? null,
|
|
7788
7969
|
sessionNamespace ?? null
|
|
7789
7970
|
])
|
|
7790
7971
|
};
|
|
7791
7972
|
}
|
|
7792
7973
|
async function resolveSkillScope(workspaceId, request) {
|
|
7793
7974
|
const root = request && opts.getWorkspaceRoot ? await opts.getWorkspaceRoot(workspaceId, request) : workspaceRoot;
|
|
7794
|
-
const
|
|
7795
|
-
return { root,
|
|
7975
|
+
const pi = opts.getPi ? await opts.getPi({ workspaceId, workspaceRoot: root, request }) : opts.pi;
|
|
7976
|
+
return { root, pi };
|
|
7796
7977
|
}
|
|
7797
7978
|
async function createRuntimeBinding(workspaceId, scope, request) {
|
|
7798
7979
|
const root = scope.root;
|
|
@@ -7837,12 +8018,19 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
7837
8018
|
pluginTools,
|
|
7838
8019
|
logger: app.log
|
|
7839
8020
|
});
|
|
7840
|
-
const
|
|
8021
|
+
const harnessFactory = opts.harnessFactory ?? ((input) => createPiCodingAgentHarness({
|
|
8022
|
+
...input,
|
|
8023
|
+
pi: {
|
|
8024
|
+
noContextFiles: true,
|
|
8025
|
+
noSkills: true,
|
|
8026
|
+
...scope.pi
|
|
8027
|
+
}
|
|
8028
|
+
}));
|
|
8029
|
+
const harness = await harnessFactory({
|
|
7841
8030
|
tools,
|
|
7842
8031
|
cwd: root,
|
|
7843
8032
|
sessionNamespace: scope.sessionNamespace,
|
|
7844
|
-
systemPromptAppend: opts.systemPromptAppend
|
|
7845
|
-
resourceLoaderOptions: scope.resourceLoaderOptions
|
|
8033
|
+
systemPromptAppend: opts.systemPromptAppend
|
|
7846
8034
|
});
|
|
7847
8035
|
const readyTracker = new ReadyStatusTracker({
|
|
7848
8036
|
sandboxReady: resolvedMode !== "vercel-sandbox",
|
|
@@ -8025,13 +8213,13 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
8025
8213
|
await app.register(modelsRoutes);
|
|
8026
8214
|
await app.register(skillsRoutes, {
|
|
8027
8215
|
workspaceRoot,
|
|
8028
|
-
additionalSkillPaths: opts.
|
|
8029
|
-
piPackages: opts.
|
|
8030
|
-
noSkills: opts.
|
|
8216
|
+
additionalSkillPaths: opts.pi?.additionalSkillPaths,
|
|
8217
|
+
piPackages: opts.pi?.packages,
|
|
8218
|
+
noSkills: opts.pi?.noSkills,
|
|
8031
8219
|
getWorkspaceRoot: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).root,
|
|
8032
|
-
getAdditionalSkillPaths: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).
|
|
8033
|
-
getPiPackages: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).
|
|
8034
|
-
getNoSkills: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).
|
|
8220
|
+
getAdditionalSkillPaths: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).pi?.additionalSkillPaths,
|
|
8221
|
+
getPiPackages: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).pi?.packages,
|
|
8222
|
+
getNoSkills: staticBinding ? void 0 : async (request) => (await getSkillsScopeForRequest(request)).pi?.noSkills
|
|
8035
8223
|
});
|
|
8036
8224
|
await app.register(sessionChangesRoutes, { tracker: sessionChangesTracker });
|
|
8037
8225
|
await app.register(
|
|
@@ -8062,6 +8250,7 @@ export {
|
|
|
8062
8250
|
createDirectSandbox,
|
|
8063
8251
|
createLogger,
|
|
8064
8252
|
createNodeWorkspace,
|
|
8253
|
+
createResourceSettingsManager,
|
|
8065
8254
|
createVercelDeploymentSnapshotProvider,
|
|
8066
8255
|
createVercelSandboxWorkspace,
|
|
8067
8256
|
fileRoutes,
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { A as AgentTool } from '../harness-DRrTn_5T.js';
|
|
2
|
+
export { a as AgentHarness, J as JSONSchema, R as RunContext, S as SendMessageInput, b as SessionCtx, c as SessionDetail, d as SessionStore, e as SessionSummary, T as ToolExecContext, f as ToolResult } from '../harness-DRrTn_5T.js';
|
|
3
|
+
import { W as Workspace, S as Sandbox, F as FileSearch } from '../agentPluginEvents-zyIvVjsA.js';
|
|
4
|
+
export { E as Entry, a as ExecOptions, b as ExecResult, I as IsolatedCodeInput, c as IsolatedCodeOutput, d as SandboxCapability, e as SandboxHandleRecord, f as SandboxHandleStore, g as Stat, h as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT } from '../agentPluginEvents-zyIvVjsA.js';
|
|
5
|
+
export { T as ToolUiMetadata, e as extractToolUiMetadata, i as isToolUiMetadata } from '../tool-ui-DIFNGwYd.js';
|
|
4
6
|
export { UIMessage, UIMessageChunk } from 'ai';
|
|
5
7
|
import { z } from 'zod';
|
|
6
8
|
|
package/dist/shared/index.js
CHANGED
|
@@ -9,9 +9,10 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
DEFAULT_AGENT_RUNTIME_CAPABILITIES,
|
|
11
11
|
PI_AGENT_RUNTIME_CAPABILITIES,
|
|
12
|
+
WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
|
|
12
13
|
extractToolUiMetadata,
|
|
13
14
|
isToolUiMetadata
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-B5JECXMG.js";
|
|
15
16
|
|
|
16
17
|
// src/shared/config-schema.ts
|
|
17
18
|
import { z } from "zod";
|
|
@@ -77,6 +78,7 @@ export {
|
|
|
77
78
|
ErrorLogFieldsSchema,
|
|
78
79
|
PI_AGENT_RUNTIME_CAPABILITIES,
|
|
79
80
|
RuntimeModeSchema,
|
|
81
|
+
WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
|
|
80
82
|
extractToolUiMetadata,
|
|
81
83
|
isToolUiMetadata,
|
|
82
84
|
validateConfig,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface ToolUiMetadata {
|
|
2
|
+
/** Renderer key registered by the app shell, e.g. `pi-subagent`. */
|
|
3
|
+
rendererId?: string;
|
|
4
|
+
/** Optional grouping label for future tool timelines/summaries. */
|
|
5
|
+
displayGroup?: string;
|
|
6
|
+
/** Optional icon hint. Frontends decide whether/how to honor it. */
|
|
7
|
+
icon?: string;
|
|
8
|
+
/** Renderer-specific structured data. */
|
|
9
|
+
details?: unknown;
|
|
10
|
+
}
|
|
11
|
+
declare function isToolUiMetadata(value: unknown): value is ToolUiMetadata;
|
|
12
|
+
/**
|
|
13
|
+
* Extract structured UI metadata from a ToolResult-like output.
|
|
14
|
+
*
|
|
15
|
+
* Shape:
|
|
16
|
+
* output.details.ui = { rendererId, displayGroup, icon, details }
|
|
17
|
+
*/
|
|
18
|
+
declare function extractToolUiMetadata(output: unknown): ToolUiMetadata | undefined;
|
|
19
|
+
|
|
20
|
+
export { type ToolUiMetadata as T, extractToolUiMetadata as e, isToolUiMetadata as i };
|