@plasm_lang/vercel-agent 0.3.77 → 0.3.80
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 +9 -2
- package/agent/instructions.md +1 -2
- package/bin/plasm-agent.mjs +5 -7
- package/package.json +29 -19
- package/scripts/build-stubs.ts +27 -0
- package/scripts/plasm-cli.ts +162 -0
- package/scripts/register-plasm-loader.mjs +6 -0
- package/scripts/run-plasm-cli.mjs +41 -0
- package/src/cli/init-scaffold.ts +198 -0
- package/src/cli/init.ts +20 -208
- package/src/cli/nitro-dev.ts +69 -0
- package/src/cli/node-dev-imports.ts +14 -0
- package/src/engine/create-host-transport.ts +7 -0
- package/src/index.ts +1 -1
- package/src/package-version.ts +14 -0
- package/src/project-info.ts +2 -1
- package/src/stubs/catalog-client.ts +2 -2
- package/src/tools/harness-tools.ts +42 -41
- package/src/tools/plasm-tools.ts +64 -55
- package/src/tools/tool-input.ts +9 -0
- package/templates/mcp-radar/.vercelignore +3 -0
- package/templates/mcp-radar/README.md +139 -0
- package/templates/mcp-radar/agent/agent.ts +38 -0
- package/templates/mcp-radar/agent/catalogs/hackernews/README.md +23 -0
- package/templates/mcp-radar/agent/catalogs/hackernews/domain.yaml +329 -0
- package/templates/mcp-radar/agent/catalogs/hackernews/eval/cases.yaml +112 -0
- package/templates/mcp-radar/agent/catalogs/hackernews/mappings.yaml +129 -0
- package/templates/mcp-radar/agent/catalogs/tavily/README.md +218 -0
- package/templates/mcp-radar/agent/catalogs/tavily/domain.yaml +373 -0
- package/templates/mcp-radar/agent/catalogs/tavily/eval/cases.yaml +56 -0
- package/templates/mcp-radar/agent/catalogs/tavily/eval/google-gemma-3-4b-it.latest.human.txt +67 -0
- package/templates/mcp-radar/agent/catalogs/tavily/eval/google-gemma-3-4b-it.latest.json +363 -0
- package/templates/mcp-radar/agent/catalogs/tavily/mappings.yaml +171 -0
- package/templates/mcp-radar/agent/channels/mcp-radar.ts +85 -0
- package/templates/mcp-radar/agent/hooks/proof-audit.ts +10 -0
- package/templates/mcp-radar/agent/instructions.md +24 -0
- package/templates/mcp-radar/agent/research/mcp-innovations-proof.md +4 -0
- package/templates/mcp-radar/agent/schedules/mcp-radar-scan.ts +14 -0
- package/templates/mcp-radar/agent/skills/mcp-proof-format.md +19 -0
- package/templates/mcp-radar/api/[[...path]].ts +23 -0
- package/templates/mcp-radar/evals/mcp-radar-discover.eval.ts +14 -0
- package/templates/mcp-radar/lib/proof-store.ts +265 -0
- package/templates/mcp-radar/lib/run-radar.ts +214 -0
- package/templates/mcp-radar/nitro.config.ts +17 -0
- package/templates/mcp-radar/package.json +14 -0
- package/templates/mcp-radar/public/index.html +10 -0
- package/templates/mcp-radar/routes/[...path].ts +29 -0
- package/templates/mcp-radar/scripts/run-evals.ts +46 -0
- package/templates/mcp-radar/scripts/smoke-channel.ts +66 -0
- package/templates/mcp-radar/vercel.json +15 -0
- package/templates/scaffold/.vercelignore +3 -0
- package/templates/scaffold/api/[[...path]].ts +23 -0
- package/templates/scaffold/nitro.config.ts +17 -0
- package/templates/scaffold/public/index.html +10 -0
- package/templates/scaffold/public/index.mcp-radar.html +10 -0
- package/templates/scaffold/routes/[...path].ts +29 -0
- package/templates/scaffold/vercel.default.json +4 -0
- package/templates/scaffold/vercel.mcp-radar.json +15 -0
package/src/cli/init.ts
CHANGED
|
@@ -1,105 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
blankPackageJsonScaffold,
|
|
6
|
+
exists,
|
|
7
|
+
patchProjectPackageJson,
|
|
8
|
+
plasmAgentPackageRoot,
|
|
9
|
+
runTemplateInit,
|
|
10
|
+
writeDeployScaffold,
|
|
11
|
+
} from "./init-scaffold.js";
|
|
6
12
|
import type { ResolvedAgentProject } from "./project-root.js";
|
|
7
13
|
|
|
8
|
-
export
|
|
9
|
-
template?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const SKIP_TEMPLATE_DIRS = new Set(["node_modules", ".plasm"]);
|
|
13
|
-
const SKIP_TEMPLATE_FILES = new Set(["package-lock.json"]);
|
|
14
|
-
|
|
15
|
-
function plasmAgentPackageRoot(): string {
|
|
16
|
-
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function resolveTemplateDir(template: string): string {
|
|
20
|
-
const templates: Record<string, string> = {
|
|
21
|
-
"mcp-radar": path.join(plasmAgentPackageRoot(), "../../../examples/mcp-radar-agent"),
|
|
22
|
-
};
|
|
23
|
-
const dir = templates[template];
|
|
24
|
-
if (!dir) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`Unknown template "${template}". Available: ${Object.keys(templates).join(", ")}`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return dir;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function shouldCopyTemplateEntry(src: string, templateRoot: string): boolean {
|
|
33
|
-
const rel = path.relative(templateRoot, src);
|
|
34
|
-
if (!rel || rel === "") return true;
|
|
35
|
-
const parts = rel.split(path.sep);
|
|
36
|
-
if (parts.some((part) => SKIP_TEMPLATE_DIRS.has(part))) return false;
|
|
37
|
-
if (SKIP_TEMPLATE_FILES.has(path.basename(src))) return false;
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function copyTemplate(templateRoot: string, projectRoot: string): Promise<void> {
|
|
42
|
-
await cp(templateRoot, projectRoot, {
|
|
43
|
-
recursive: true,
|
|
44
|
-
filter: (src) => src === templateRoot || shouldCopyTemplateEntry(src, templateRoot),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function patchBootstrapPackageJson(
|
|
49
|
-
projectRoot: string,
|
|
50
|
-
packageRoot: string,
|
|
51
|
-
): Promise<void> {
|
|
52
|
-
const pkgPath = path.join(projectRoot, "package.json");
|
|
53
|
-
const raw = await readFile(pkgPath, "utf8");
|
|
54
|
-
const pkg = JSON.parse(raw) as {
|
|
55
|
-
name?: string;
|
|
56
|
-
scripts?: Record<string, string>;
|
|
57
|
-
dependencies?: Record<string, string>;
|
|
58
|
-
};
|
|
59
|
-
pkg.name = path.basename(projectRoot);
|
|
60
|
-
const engineRoot = path.resolve(packageRoot, "../plasm-engine");
|
|
61
|
-
pkg.dependencies = {
|
|
62
|
-
...pkg.dependencies,
|
|
63
|
-
"@plasm_lang/vercel-agent": `file:${path.resolve(packageRoot)}`,
|
|
64
|
-
"@plasm_lang/engine": `file:${engineRoot}`,
|
|
65
|
-
"@vercel/blob": "^0.27.3",
|
|
66
|
-
"@vercel/functions": "^3.4.3",
|
|
67
|
-
"@vercel/kv": "^3.0.0",
|
|
68
|
-
};
|
|
69
|
-
const nodeRunner =
|
|
70
|
-
"node --experimental-strip-types --experimental-transform-types ./node_modules/@plasm_lang/vercel-agent/scripts/plasm-node.mjs";
|
|
71
|
-
pkg.scripts = {
|
|
72
|
-
build: "plasm-agent build",
|
|
73
|
-
"vercel-build": "plasm-agent build",
|
|
74
|
-
dev: "plasm-agent dev",
|
|
75
|
-
info: "plasm-agent info",
|
|
76
|
-
deploy: "vercel deploy",
|
|
77
|
-
...pkg.scripts,
|
|
78
|
-
eval: `${nodeRunner} scripts/run-evals.ts`,
|
|
79
|
-
"smoke:channel": `${nodeRunner} scripts/smoke-channel.ts`,
|
|
80
|
-
};
|
|
81
|
-
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function runTemplateInit(
|
|
85
|
-
targetDir: string,
|
|
86
|
-
template: string,
|
|
87
|
-
): Promise<ResolvedAgentProject> {
|
|
88
|
-
const projectRoot = path.resolve(targetDir);
|
|
89
|
-
const agentRoot = path.join(projectRoot, "agent");
|
|
90
|
-
if (await exists(path.join(agentRoot, "agent.ts"))) {
|
|
91
|
-
throw new Error(`agent/agent.ts already exists in ${projectRoot}`);
|
|
92
|
-
}
|
|
93
|
-
const templateRoot = resolveTemplateDir(template);
|
|
94
|
-
if (!(await exists(templateRoot))) {
|
|
95
|
-
throw new Error(`Template source missing: ${templateRoot}`);
|
|
96
|
-
}
|
|
97
|
-
await mkdir(projectRoot, { recursive: true });
|
|
98
|
-
await copyTemplate(templateRoot, projectRoot);
|
|
99
|
-
await patchBootstrapPackageJson(projectRoot, plasmAgentPackageRoot());
|
|
100
|
-
await writeVercelScaffold(projectRoot, template);
|
|
101
|
-
return { projectRoot, agentRoot };
|
|
102
|
-
}
|
|
14
|
+
export type { InitOptions } from "./init-scaffold.js";
|
|
103
15
|
|
|
104
16
|
const AGENT_TS = `import path from "node:path";
|
|
105
17
|
import { fileURLToPath } from "node:url";
|
|
@@ -196,113 +108,12 @@ PLASM_TENANT_SCOPE=local
|
|
|
196
108
|
PORT=3000
|
|
197
109
|
`;
|
|
198
110
|
|
|
199
|
-
const VERCEL_JSON_DEFAULT = `{
|
|
200
|
-
"buildCommand": "plasm-agent build",
|
|
201
|
-
"rewrites": [{ "source": "/(.*)", "destination": "/api/$1" }]
|
|
202
|
-
}
|
|
203
|
-
`;
|
|
204
|
-
|
|
205
|
-
const VERCEL_JSON_MCP_RADAR = `{
|
|
206
|
-
"buildCommand": "plasm-agent build",
|
|
207
|
-
"rewrites": [{ "source": "/(.*)", "destination": "/api/$1" }],
|
|
208
|
-
"crons": [
|
|
209
|
-
{
|
|
210
|
-
"path": "/internal/cron/mcp-radar-scan",
|
|
211
|
-
"schedule": "0 */6 * * *"
|
|
212
|
-
}
|
|
213
|
-
],
|
|
214
|
-
"functions": {
|
|
215
|
-
"api/**": {
|
|
216
|
-
"maxDuration": 300
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
`;
|
|
221
|
-
|
|
222
|
-
const VERCELIGNORE = `node_modules
|
|
223
|
-
.env*
|
|
224
|
-
agent/.plasm/research
|
|
225
|
-
`;
|
|
226
|
-
|
|
227
|
-
const API_HANDLER_TS = `import path from "node:path";
|
|
228
|
-
import { fileURLToPath } from "node:url";
|
|
229
|
-
|
|
230
|
-
import agentDefinition from "../agent/agent.js";
|
|
231
|
-
import { createPlasmApp, vercelPlasmHandler } from "@plasm_lang/vercel-agent";
|
|
232
|
-
|
|
233
|
-
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
234
|
-
const agentRoot = path.join(packageRoot, "agent");
|
|
235
|
-
|
|
236
|
-
let app: Awaited<ReturnType<typeof createPlasmApp>> | undefined;
|
|
237
|
-
|
|
238
|
-
export default async function handler(
|
|
239
|
-
req: import("node:http").IncomingMessage,
|
|
240
|
-
res: import("node:http").ServerResponse,
|
|
241
|
-
): Promise<void> {
|
|
242
|
-
app ??= await createPlasmApp({
|
|
243
|
-
agentRoot,
|
|
244
|
-
definition: agentDefinition,
|
|
245
|
-
mode: "prod",
|
|
246
|
-
sessions: false,
|
|
247
|
-
});
|
|
248
|
-
await vercelPlasmHandler(app)(req, res);
|
|
249
|
-
}
|
|
250
|
-
`;
|
|
251
|
-
|
|
252
|
-
const PACKAGE_JSON_TEMPLATE = {
|
|
253
|
-
name: "my-plasm-agent",
|
|
254
|
-
private: true,
|
|
255
|
-
type: "module",
|
|
256
|
-
scripts: {
|
|
257
|
-
dev: "plasm-agent dev",
|
|
258
|
-
build: "plasm-agent build",
|
|
259
|
-
"vercel-build": "plasm-agent build",
|
|
260
|
-
info: "plasm-agent info",
|
|
261
|
-
deploy: "vercel deploy",
|
|
262
|
-
},
|
|
263
|
-
dependencies: {} as Record<string, string>,
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
async function writeVercelScaffold(
|
|
267
|
-
projectRoot: string,
|
|
268
|
-
template?: string,
|
|
269
|
-
): Promise<void> {
|
|
270
|
-
const vercelJson =
|
|
271
|
-
template === "mcp-radar" ? VERCEL_JSON_MCP_RADAR : VERCEL_JSON_DEFAULT;
|
|
272
|
-
await mkdir(path.join(projectRoot, "api"), { recursive: true });
|
|
273
|
-
await writeFile(path.join(projectRoot, "vercel.json"), vercelJson, "utf8");
|
|
274
|
-
await writeFile(path.join(projectRoot, ".vercelignore"), VERCELIGNORE, "utf8");
|
|
275
|
-
await writeFile(
|
|
276
|
-
path.join(projectRoot, "api", "[[...path]].ts"),
|
|
277
|
-
API_HANDLER_TS,
|
|
278
|
-
"utf8",
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function packageJsonScaffold(): Record<string, unknown> {
|
|
283
|
-
return {
|
|
284
|
-
...PACKAGE_JSON_TEMPLATE,
|
|
285
|
-
dependencies: {
|
|
286
|
-
"@plasm_lang/vercel-agent": `^${FRAMEWORK_VERSION}`,
|
|
287
|
-
},
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
async function exists(p: string): Promise<boolean> {
|
|
292
|
-
try {
|
|
293
|
-
await access(p);
|
|
294
|
-
return true;
|
|
295
|
-
} catch {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
111
|
export async function runPlasmInit(
|
|
301
112
|
targetDir: string,
|
|
302
|
-
options?: InitOptions,
|
|
113
|
+
options?: import("./init-scaffold.js").InitOptions,
|
|
303
114
|
): Promise<ResolvedAgentProject> {
|
|
304
115
|
if (options?.template) {
|
|
305
|
-
return runTemplateInit(targetDir, options.template);
|
|
116
|
+
return runTemplateInit(targetDir, options.template, options);
|
|
306
117
|
}
|
|
307
118
|
|
|
308
119
|
const projectRoot = path.resolve(targetDir);
|
|
@@ -328,20 +139,19 @@ export async function runPlasmInit(
|
|
|
328
139
|
if (!(await exists(path.join(projectRoot, "package.json")))) {
|
|
329
140
|
await writeFile(
|
|
330
141
|
path.join(projectRoot, "package.json"),
|
|
331
|
-
`${JSON.stringify(
|
|
142
|
+
`${JSON.stringify(blankPackageJsonScaffold(), null, 2)}\n`,
|
|
332
143
|
"utf8",
|
|
333
144
|
);
|
|
334
|
-
await
|
|
145
|
+
await patchProjectPackageJson(projectRoot, plasmAgentPackageRoot(), { npm: options?.npm });
|
|
335
146
|
}
|
|
336
147
|
|
|
337
|
-
await
|
|
338
|
-
|
|
148
|
+
await writeDeployScaffold(projectRoot);
|
|
339
149
|
return { projectRoot, agentRoot };
|
|
340
150
|
}
|
|
341
151
|
|
|
342
152
|
export function formatInitSuccess(
|
|
343
153
|
project: ResolvedAgentProject,
|
|
344
|
-
options?: InitOptions,
|
|
154
|
+
options?: import("./init-scaffold.js").InitOptions,
|
|
345
155
|
): string {
|
|
346
156
|
if (options?.template === "mcp-radar") {
|
|
347
157
|
return [
|
|
@@ -353,7 +163,8 @@ export function formatInitSuccess(
|
|
|
353
163
|
" plasm-agent link # pull AI_GATEWAY_API_KEY from Vercel",
|
|
354
164
|
" plasm-agent build",
|
|
355
165
|
" npm run smoke:channel",
|
|
356
|
-
" plasm-agent dev #
|
|
166
|
+
" plasm-agent dev # Nitro dev server (Vercel routing parity)",
|
|
167
|
+
" plasm-agent dev --interactive # optional TUI + sessions + hot reload",
|
|
357
168
|
" vercel deploy # production (channels + cron)",
|
|
358
169
|
].join("\n");
|
|
359
170
|
}
|
|
@@ -366,7 +177,8 @@ export function formatInitSuccess(
|
|
|
366
177
|
" npm install",
|
|
367
178
|
" plasm-agent link # pull AI_GATEWAY_API_KEY from Vercel",
|
|
368
179
|
" plasm-agent build # generate CGS stubs + discovery manifest",
|
|
369
|
-
" plasm-agent dev #
|
|
180
|
+
" plasm-agent dev # Nitro dev server (Vercel routing parity)",
|
|
181
|
+
" plasm-agent dev --interactive # optional TUI + sessions",
|
|
370
182
|
" vercel deploy # production on Vercel",
|
|
371
183
|
].join("\n");
|
|
372
184
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawn, type ChildProcess } from "node:child_process";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { nitroDevNodeOptions } from "./node-dev-imports.js";
|
|
7
|
+
import type { ResolvedAgentProject } from "./project-root.js";
|
|
8
|
+
|
|
9
|
+
function plasmAgentPackageRoot(): string {
|
|
10
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function assertNitroScaffold(projectRoot: string): Promise<void> {
|
|
14
|
+
const required = [
|
|
15
|
+
path.join(projectRoot, "nitro.config.ts"),
|
|
16
|
+
path.join(projectRoot, "routes", "[...path].ts"),
|
|
17
|
+
];
|
|
18
|
+
for (const filePath of required) {
|
|
19
|
+
try {
|
|
20
|
+
await access(filePath);
|
|
21
|
+
} catch {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Missing ${path.relative(projectRoot, filePath)} — run \`plasm-agent init\` to scaffold Nitro dev`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function nitroBin(projectRoot: string): string {
|
|
30
|
+
return path.join(projectRoot, "node_modules", ".bin", "nitro");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function startNitroDevForProject(project: ResolvedAgentProject): Promise<void> {
|
|
34
|
+
await assertNitroScaffold(project.projectRoot);
|
|
35
|
+
|
|
36
|
+
const nodeOptions = nitroDevNodeOptions(plasmAgentPackageRoot());
|
|
37
|
+
|
|
38
|
+
const bin = nitroBin(project.projectRoot);
|
|
39
|
+
try {
|
|
40
|
+
await access(bin);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new Error(
|
|
43
|
+
"nitropack is not installed — run `npm install` in the project root (init adds nitropack as a devDependency)",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const child: ChildProcess = spawn(bin, ["dev"], {
|
|
48
|
+
cwd: project.projectRoot,
|
|
49
|
+
env: {
|
|
50
|
+
...process.env,
|
|
51
|
+
NODE_OPTIONS: nodeOptions,
|
|
52
|
+
},
|
|
53
|
+
stdio: "inherit",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const wait = new Promise<number>((resolve, reject) => {
|
|
57
|
+
child.on("error", reject);
|
|
58
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
for (const signal of ["SIGINT", "SIGTERM"] as const) {
|
|
62
|
+
process.on(signal, () => {
|
|
63
|
+
child.kill(signal);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const exitCode = await wait;
|
|
68
|
+
process.exit(exitCode);
|
|
69
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
/** NODE_OPTIONS imports for Nitro dev (tsx + Plasm .ts resolution). */
|
|
8
|
+
export function nitroDevNodeOptions(packageRoot: string): string {
|
|
9
|
+
const tsxImport = require.resolve("tsx/esm");
|
|
10
|
+
const plasmLoader = pathToFileURL(
|
|
11
|
+
path.join(packageRoot, "scripts", "register-plasm-loader.mjs"),
|
|
12
|
+
).href;
|
|
13
|
+
return [`--import=${tsxImport}`, `--import=${plasmLoader}`].join(" ");
|
|
14
|
+
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { createDefaultHostTransport } from "./host-transport.js";
|
|
2
|
+
import { connectAuthOptionsForEntry } from "./connect-auth.js";
|
|
2
3
|
import type { HostTransportFn } from "./napi-binding.js";
|
|
3
4
|
|
|
5
|
+
/** Outbound HTTP for CGS stub live execute: Connect only when configured for the catalog. */
|
|
6
|
+
export function createStubHostTransport(entryId?: string): HostTransportFn {
|
|
7
|
+
const useConnect = connectAuthOptionsForEntry(entryId)?.connector != null;
|
|
8
|
+
return createDefaultHostTransport({ useConnect });
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
/** Production host transport: env bearer → Vercel Connect `getToken()` → fetch. */
|
|
5
12
|
export function createProductionHostTransport(): HostTransportFn {
|
|
6
13
|
return createDefaultHostTransport({ useConnect: true });
|
package/src/index.ts
CHANGED
|
@@ -130,7 +130,7 @@ export type {
|
|
|
130
130
|
export { StubPlasmEngine, NapiPlasmEngine, createEngine, isNativeEngineAvailable } from "./engine/napi-binding.js";
|
|
131
131
|
export { createDefaultHostTransport } from "./engine/host-transport.js";
|
|
132
132
|
export type { HostTransportOptions } from "./engine/host-transport.js";
|
|
133
|
-
export { createProductionHostTransport } from "./engine/create-host-transport.js";
|
|
133
|
+
export { createProductionHostTransport, createStubHostTransport } from "./engine/create-host-transport.js";
|
|
134
134
|
export { loadAgentEnv } from "./load-env.js";
|
|
135
135
|
export {
|
|
136
136
|
connectorUidForEntry,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
let cachedVersion: string | undefined;
|
|
6
|
+
|
|
7
|
+
/** Published semver from @plasm_lang/vercel-agent package.json. */
|
|
8
|
+
export function frameworkPackageVersion(): string {
|
|
9
|
+
if (cachedVersion) return cachedVersion;
|
|
10
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
const raw = readFileSync(path.join(packageRoot, "package.json"), "utf8");
|
|
12
|
+
cachedVersion = (JSON.parse(raw) as { version: string }).version;
|
|
13
|
+
return cachedVersion;
|
|
14
|
+
}
|
package/src/project-info.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { isNativeEngineAvailable } from "./engine/napi-binding.js";
|
|
|
10
10
|
import { exportScheduleCronManifest } from "./authoring/schedule-manager.js";
|
|
11
11
|
import { isGatewayConfigured } from "./gateway-model.js";
|
|
12
12
|
import type { LoadedProjectSlots } from "./authoring/slot-loader.js";
|
|
13
|
+
import { frameworkPackageVersion } from "./package-version.js";
|
|
13
14
|
import { resolveCatalogLiveHash } from "./stubs/catalog-hash.js";
|
|
14
15
|
import { stubFreshness } from "./stubs/generator.js";
|
|
15
16
|
|
|
@@ -21,7 +22,7 @@ export const PLASM_LANGUAGE_TOOLS = [
|
|
|
21
22
|
] as const;
|
|
22
23
|
|
|
23
24
|
export const FRAMEWORK_NAME = "@plasm_lang/vercel-agent";
|
|
24
|
-
export const FRAMEWORK_VERSION =
|
|
25
|
+
export const FRAMEWORK_VERSION = frameworkPackageVersion();
|
|
25
26
|
|
|
26
27
|
export interface CatalogInfoEntry {
|
|
27
28
|
name: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HostTransportFn } from "../engine/napi-binding.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createStubHostTransport } from "../engine/create-host-transport.js";
|
|
3
3
|
import {
|
|
4
4
|
createEngine,
|
|
5
5
|
type DryRunResult,
|
|
@@ -143,7 +143,7 @@ export async function executeRows<TRow>(
|
|
|
143
143
|
options?.transport ??
|
|
144
144
|
(process.env.PLASM_STUB_USE_MOCK_TRANSPORT === "1"
|
|
145
145
|
? createFixtureMockTransport()
|
|
146
|
-
:
|
|
146
|
+
: createStubHostTransport(builder.entryId));
|
|
147
147
|
|
|
148
148
|
if (typeof bound.run !== "function") {
|
|
149
149
|
throw new Error("executeRows: program builder missing run()");
|
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
import { tool } from "ai";
|
|
1
|
+
import { tool, type ToolSet } from "ai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
import type { SkillDefinition } from "../authoring/define-skill.js";
|
|
5
5
|
import type { SubagentRegistry } from "../authoring/subagent-loader.js";
|
|
6
|
+
import { toolInput } from "./tool-input.js";
|
|
7
|
+
|
|
8
|
+
const readSkillInputSchema = z.object({
|
|
9
|
+
name: z.string().min(1).describe("Skill name from the index"),
|
|
10
|
+
});
|
|
6
11
|
|
|
7
12
|
export function createHarnessTools(options: {
|
|
8
13
|
skills?: SkillDefinition[];
|
|
9
14
|
subagents?: SubagentRegistry;
|
|
10
|
-
}) {
|
|
15
|
+
}): ToolSet {
|
|
16
|
+
const tools: ToolSet = {};
|
|
11
17
|
const skillByName = new Map((options.skills ?? []).map((s) => [s.name, s]));
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
execute: async ({ name }: { name: string }) => {
|
|
23
|
-
const skill = skillByName.get(name);
|
|
24
|
-
if (!skill) {
|
|
25
|
-
return `Unknown skill "${name}". Available: ${[...skillByName.keys()].join(", ")}`;
|
|
26
|
-
}
|
|
27
|
-
return skill.body.trim();
|
|
28
|
-
},
|
|
29
|
-
}),
|
|
19
|
+
if (skillByName.size > 0) {
|
|
20
|
+
tools.read_skill = tool({
|
|
21
|
+
description:
|
|
22
|
+
"Load full text for a filesystem skill by name. Use when the skill index in the system prompt is not enough.",
|
|
23
|
+
inputSchema: toolInput(readSkillInputSchema),
|
|
24
|
+
execute: async ({ name }: { name: string }) => {
|
|
25
|
+
const skill = skillByName.get(name);
|
|
26
|
+
if (!skill) {
|
|
27
|
+
return `Unknown skill "${name}". Available: ${[...skillByName.keys()].join(", ")}`;
|
|
30
28
|
}
|
|
31
|
-
|
|
29
|
+
return skill.body.trim();
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
32
33
|
|
|
33
34
|
const subagentNames = options.subagents?.list().map((s) => s.name) ?? [];
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
35
|
+
if (subagentNames.length > 0 && options.subagents) {
|
|
36
|
+
const subagents = options.subagents;
|
|
37
|
+
tools.delegate_subagent = tool({
|
|
38
|
+
description:
|
|
39
|
+
"Delegate a sub-task to a filesystem-isolated child agent. Each subagent has its own catalogs and session scope.",
|
|
40
|
+
inputSchema: toolInput(
|
|
41
|
+
z.object({
|
|
42
|
+
name: z
|
|
43
|
+
.string()
|
|
44
|
+
.min(1)
|
|
45
|
+
.describe(`Subagent name. One of: ${subagentNames.join(", ")}`),
|
|
46
|
+
message: z.string().min(1).describe("User message for the child agent turn"),
|
|
47
|
+
}),
|
|
48
|
+
),
|
|
49
|
+
execute: async ({ name, message }: { name: string; message: string }) => {
|
|
50
|
+
const result = await subagents.delegate(name, message);
|
|
51
|
+
return `${result.text}\n\n(steps: ${result.steps})`;
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
return
|
|
56
|
+
return tools;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export function renderSkillIndex(skills: SkillDefinition[]): string {
|