@plasm_lang/vercel-agent 0.3.82 → 0.3.85
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 +1 -1
- package/agent/hooks/trace-log.ts +1 -1
- package/agent/instructions.md +1 -1
- package/package.json +8 -4
- package/scripts/plasm-cli.ts +6 -0
- package/src/archive/paths.ts +4 -1
- package/src/authoring/slot-loader.ts +57 -4
- package/src/cli/build.ts +41 -2
- package/src/cli/compile-authored-slots.ts +79 -0
- package/src/cli/init-scaffold.ts +5 -6
- package/src/cli/init.ts +3 -1
- package/src/cli/nitro-dev.ts +23 -62
- package/src/gateway-model.ts +17 -6
- package/src/index.ts +5 -0
- package/src/instrumentation.ts +1 -1
- package/src/nitro/agent-summary.ts +133 -0
- package/src/nitro/build-application.ts +98 -0
- package/src/nitro/build-nitro-output.ts +14 -0
- package/src/nitro/copy-vercel-function-assets.ts +31 -0
- package/src/nitro/create-plasm-nitro.ts +111 -0
- package/src/nitro/patch-vercel-config.ts +37 -0
- package/src/nitro/paths.ts +30 -0
- package/src/nitro/prepare-host.ts +69 -0
- package/src/nitro/vercel-build-output-config.ts +18 -0
- package/src/nitro/workflow-directives.ts +43 -0
- package/src/nitro/write-nitro-entry.ts +87 -0
- package/src/package-version.ts +3 -11
- package/src/runtime/agent-runtime.ts +13 -12
- package/src/runtime/compaction.ts +1 -1
- package/src/server/plasm-handler.ts +22 -2
- package/src/telemetry/plasm-spans.ts +3 -3
- package/src/tools/descriptions.ts +29 -42
- package/src/tools/format.ts +2 -2
- package/src/tools/plasm-tools.ts +4 -4
- package/src/workflow/world-bootstrap.ts +12 -1
- package/templates/mcp-radar/agent/instrumentation.ts +18 -0
- package/templates/mcp-radar/lib/proof-store.ts +10 -3
- package/templates/mcp-radar/vercel.json +2 -13
- package/templates/scaffold/agent/instrumentation.ts +18 -0
- package/templates/scaffold/vercel.default.json +2 -2
- package/templates/scaffold/vercel.mcp-radar.json +2 -13
- package/templates/mcp-radar/api/[[...path]].ts +0 -23
- package/templates/mcp-radar/nitro.config.ts +0 -17
- package/templates/mcp-radar/routes/[...path].ts +0 -29
- package/templates/scaffold/api/[[...path]].ts +0 -23
- package/templates/scaffold/nitro.config.ts +0 -17
- package/templates/scaffold/routes/[...path].ts +0 -29
package/src/package-version.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
1
|
+
import plasmAgentPackage from "../package.json" with { type: "json" };
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/** Published semver from @plasm_lang/vercel-agent package.json. */
|
|
3
|
+
/** Published semver from @plasm_lang/vercel-agent package.json (inlined when Nitro bundles). */
|
|
8
4
|
export function frameworkPackageVersion(): string {
|
|
9
|
-
|
|
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;
|
|
5
|
+
return plasmAgentPackage.version;
|
|
14
6
|
}
|
|
@@ -21,6 +21,7 @@ import { createArchiveStore } from "../archive/resolve-backend.js";
|
|
|
21
21
|
import type { ProdArchiveStore } from "../archive/prod-archive-store.js";
|
|
22
22
|
import { computeRunId } from "../archive/run-id.js";
|
|
23
23
|
import { activeTraceId, plasmSpans } from "../telemetry/plasm-spans.js";
|
|
24
|
+
import { PlasmSpanAttributes } from "../instrumentation.js";
|
|
24
25
|
import type { AuthoringContext } from "../authoring/context.js";
|
|
25
26
|
import type { HookRunner } from "../authoring/hook-runner.js";
|
|
26
27
|
import type { AgentWorkflowWorldDefinition } from "../define-agent.js";
|
|
@@ -61,7 +62,7 @@ export interface PlasmPlanInput {
|
|
|
61
62
|
|
|
62
63
|
export interface PlasmRunInput {
|
|
63
64
|
logicalSessionRef: string;
|
|
64
|
-
|
|
65
|
+
runRef: string;
|
|
65
66
|
reasoning?: string;
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -283,7 +284,7 @@ export class AgentRuntime {
|
|
|
283
284
|
});
|
|
284
285
|
await this.sessionManager.update(session);
|
|
285
286
|
|
|
286
|
-
span.setAttribute(
|
|
287
|
+
span.setAttribute(PlasmSpanAttributes.RUN_REF, dry.planCommitRef);
|
|
287
288
|
if (catalogCgsHash) {
|
|
288
289
|
span.setAttribute("plasm.catalog_cgs_hash", catalogCgsHash);
|
|
289
290
|
}
|
|
@@ -310,7 +311,7 @@ export class AgentRuntime {
|
|
|
310
311
|
});
|
|
311
312
|
|
|
312
313
|
await this.emitHook("plan:commit", {
|
|
313
|
-
|
|
314
|
+
runRef: dry.planCommitRef,
|
|
314
315
|
program: input.program,
|
|
315
316
|
logicalSessionRef: session.logicalSessionRef,
|
|
316
317
|
});
|
|
@@ -325,14 +326,14 @@ export class AgentRuntime {
|
|
|
325
326
|
void input.reasoning;
|
|
326
327
|
const entryId = session.seeds[0]?.api;
|
|
327
328
|
const catalogCgsHash = entryId ? this.catalogHashForEntry(entryId) : undefined;
|
|
328
|
-
const planCommit = session.planCommits.find((pc) => pc.ref === input.
|
|
329
|
+
const planCommit = session.planCommits.find((pc) => pc.ref === input.runRef);
|
|
329
330
|
|
|
330
331
|
return plasmSpans.liveRun(
|
|
331
332
|
{
|
|
332
333
|
intent: session.intent,
|
|
333
334
|
logicalSessionRef: session.logicalSessionRef,
|
|
334
335
|
sessionId: session.logicalSessionId,
|
|
335
|
-
|
|
336
|
+
runRef: input.runRef,
|
|
336
337
|
entryId,
|
|
337
338
|
catalogCgsHash,
|
|
338
339
|
},
|
|
@@ -340,8 +341,8 @@ export class AgentRuntime {
|
|
|
340
341
|
const started = Date.now();
|
|
341
342
|
const result =
|
|
342
343
|
this.hostTransport && typeof this.engine.runPlanLive === "function"
|
|
343
|
-
? await this.engine.runPlanLive(input.
|
|
344
|
-
: await this.engine.runPlan(input.
|
|
344
|
+
? await this.engine.runPlanLive(input.runRef, this.hostTransport)
|
|
345
|
+
: await this.engine.runPlan(input.runRef);
|
|
345
346
|
const program = planCommit?.program ?? "";
|
|
346
347
|
const runMeta = parseRunMeta(result.metaJson);
|
|
347
348
|
const requestFingerprints = collectRequestFingerprints(runMeta);
|
|
@@ -349,7 +350,7 @@ export class AgentRuntime {
|
|
|
349
350
|
catalogCgsHash && program
|
|
350
351
|
? computeRunId({
|
|
351
352
|
catalogCgsHash,
|
|
352
|
-
planCommitRef: input.
|
|
353
|
+
planCommitRef: input.runRef,
|
|
353
354
|
program,
|
|
354
355
|
entryId,
|
|
355
356
|
requestFingerprints,
|
|
@@ -357,7 +358,7 @@ export class AgentRuntime {
|
|
|
357
358
|
: `pr${createHash("sha256").update(randomUUID()).digest("hex")}`;
|
|
358
359
|
|
|
359
360
|
span.setAttribute("plasm.run_id", runId);
|
|
360
|
-
span.setAttribute(
|
|
361
|
+
span.setAttribute(PlasmSpanAttributes.RUN_REF, input.runRef);
|
|
361
362
|
if (catalogCgsHash) {
|
|
362
363
|
span.setAttribute("plasm.catalog_cgs_hash", catalogCgsHash);
|
|
363
364
|
}
|
|
@@ -365,7 +366,7 @@ export class AgentRuntime {
|
|
|
365
366
|
if (this.archive) {
|
|
366
367
|
await this.archive.writeRunSnapshot({
|
|
367
368
|
run_id: runId,
|
|
368
|
-
plan_commit_ref: input.
|
|
369
|
+
plan_commit_ref: input.runRef,
|
|
369
370
|
catalog_cgs_hash: catalogCgsHash ?? "unknown",
|
|
370
371
|
entry_id: entryId,
|
|
371
372
|
logical_session_ref: session.logicalSessionRef,
|
|
@@ -386,7 +387,7 @@ export class AgentRuntime {
|
|
|
386
387
|
await this.recordToolTrace("plasm", "plasm.live_run", started, {
|
|
387
388
|
intent: session.intent,
|
|
388
389
|
logical_session_ref: session.logicalSessionRef,
|
|
389
|
-
plan_commit_ref: input.
|
|
390
|
+
plan_commit_ref: input.runRef,
|
|
390
391
|
run_id: runId,
|
|
391
392
|
catalog_cgs_hash: catalogCgsHash,
|
|
392
393
|
ok: result.ok,
|
|
@@ -394,7 +395,7 @@ export class AgentRuntime {
|
|
|
394
395
|
});
|
|
395
396
|
|
|
396
397
|
await this.emitHook("run:complete", {
|
|
397
|
-
|
|
398
|
+
runRef: input.runRef,
|
|
398
399
|
runId,
|
|
399
400
|
ok: result.ok,
|
|
400
401
|
logicalSessionRef: session.logicalSessionRef,
|
|
@@ -66,7 +66,7 @@ export async function maybeCompactMessages(
|
|
|
66
66
|
const summary = await generateText({
|
|
67
67
|
model: summaryModel,
|
|
68
68
|
system:
|
|
69
|
-
"Summarize the prior agent conversation for continuation. Preserve goals, catalog picks, logical_session_ref,
|
|
69
|
+
"Summarize the prior agent conversation for continuation. Preserve goals, catalog picks, logical_session_ref, run_ref, and unresolved tasks. Be concise.",
|
|
70
70
|
prompt: transcript,
|
|
71
71
|
temperature: 0,
|
|
72
72
|
});
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createAgentFromDefinition,
|
|
7
7
|
resolveAgentDefinition,
|
|
8
8
|
} from "../define-agent.js";
|
|
9
|
+
import { readBuildManifest } from "../cli/build.js";
|
|
9
10
|
import { createAuthoringContext, type AuthoringContext } from "../authoring/context.js";
|
|
10
11
|
import { tryHandleChannelRoute } from "../authoring/channel-dispatch.js";
|
|
11
12
|
import {
|
|
@@ -75,9 +76,24 @@ export function normalizePlasmPathname(url: string | undefined): string {
|
|
|
75
76
|
return pathname;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
/** Resolve request path on Vercel (rewrite-to-/api preserves public path in req.url). */
|
|
80
|
+
function vercelIncomingUrl(req: IncomingMessage): string {
|
|
81
|
+
for (const key of [
|
|
82
|
+
"x-vercel-original-url",
|
|
83
|
+
"x-middleware-request-url",
|
|
84
|
+
"x-forwarded-uri",
|
|
85
|
+
] as const) {
|
|
86
|
+
const raw = req.headers[key];
|
|
87
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
88
|
+
return raw.startsWith("/") ? raw : new URL(raw, "http://localhost").pathname;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return req.url ?? "/";
|
|
92
|
+
}
|
|
93
|
+
|
|
78
94
|
export function rewriteRequestPath(req: IncomingMessage): IncomingMessage {
|
|
79
|
-
const
|
|
80
|
-
const
|
|
95
|
+
const original = vercelIncomingUrl(req);
|
|
96
|
+
const pathname = normalizePlasmPathname(original);
|
|
81
97
|
const query = original.includes("?") ? original.slice(original.indexOf("?")) : "";
|
|
82
98
|
const proxy = Object.create(req) as IncomingMessage;
|
|
83
99
|
Object.defineProperty(proxy, "url", {
|
|
@@ -235,9 +251,13 @@ export async function createPlasmApp(options: PlasmAppOptions): Promise<PlasmApp
|
|
|
235
251
|
|
|
236
252
|
const refreshSlots = async (): Promise<LoadedProjectSlots> => {
|
|
237
253
|
const currentDiscovery = discovery ?? (await refreshDiscovery());
|
|
254
|
+
const buildManifest = await readBuildManifest(agentRoot);
|
|
238
255
|
loadedSlots = await loadAuthoredSlots({
|
|
239
256
|
discovery: currentDiscovery,
|
|
240
257
|
importCacheBust,
|
|
258
|
+
agentRoot,
|
|
259
|
+
projectRoot,
|
|
260
|
+
compiledSlots: buildManifest?.compiledSlots,
|
|
241
261
|
});
|
|
242
262
|
return loadedSlots;
|
|
243
263
|
};
|
|
@@ -8,7 +8,7 @@ export interface PlasmSpanContext {
|
|
|
8
8
|
logicalSessionRef?: string;
|
|
9
9
|
catalogCgsHash?: string;
|
|
10
10
|
entryId?: string;
|
|
11
|
-
|
|
11
|
+
runRef?: string;
|
|
12
12
|
runId?: string;
|
|
13
13
|
toolName?: string;
|
|
14
14
|
transportHost?: string;
|
|
@@ -26,8 +26,8 @@ function applyPlasmAttributes(span: Span, ctx: PlasmSpanContext): void {
|
|
|
26
26
|
if (ctx.catalogCgsHash) {
|
|
27
27
|
span.setAttribute(PlasmSpanAttributes.CATALOG_CGS_HASH, ctx.catalogCgsHash);
|
|
28
28
|
}
|
|
29
|
-
if (ctx.
|
|
30
|
-
span.setAttribute(PlasmSpanAttributes.
|
|
29
|
+
if (ctx.runRef) {
|
|
30
|
+
span.setAttribute(PlasmSpanAttributes.RUN_REF, ctx.runRef);
|
|
31
31
|
}
|
|
32
32
|
if (ctx.runId) span.setAttribute(PlasmSpanAttributes.RUN_ID, ctx.runId);
|
|
33
33
|
if (ctx.entryId) span.setAttribute(PlasmSpanAttributes.ENTRY_ID, ctx.entryId);
|
|
@@ -17,7 +17,7 @@ Returns **\`logical_session_ref\`** + fenced teaching TSV. TSV is the active sym
|
|
|
17
17
|
|
|
18
18
|
**\`_meta.plasm\`:** \`logical_session_ref\`, \`continuity\`, \`domain_revision\`, optional **\`relations\`**.`;
|
|
19
19
|
|
|
20
|
-
export const PLASM_TOOL_DESCRIPTION = `**Plan Plasm** (dry-run): **\`logical_session_ref\`** + **\`program\`**. Returns reviewable plan topology and executable **\`
|
|
20
|
+
export const PLASM_TOOL_DESCRIPTION = `**Plan Plasm** (dry-run): **\`logical_session_ref\`** + **\`program\`**. Returns reviewable plan topology and executable **\`run_ref\`** (\`pcN\`). Pass that token to **\`plasm_run\`**; do **not** echo the program.
|
|
21
21
|
|
|
22
22
|
**\`program\` is Plasm source text, not JSON data.** Write one raw expression (e.g. \`e3(p15="electric").r2[p4,p5]\`) or multiline bindings with final roots. If a plan merely echoes an object/array/string literal, that is a literal no-op; rewrite as Plasm source.
|
|
23
23
|
|
|
@@ -29,66 +29,53 @@ Output:
|
|
|
29
29
|
|
|
30
30
|
TSV table semantics:
|
|
31
31
|
- Header: \`plasm_expr<TAB>Meaning\`; one tab per row. Left = syntax/metadata; right = guidance only (never copy \`Meaning\`).
|
|
32
|
-
- Executable rows start with \`e
|
|
32
|
+
- Executable rows start with \`e#\`; metadata-only \`p#\`/\`r#\`/\`v#\` rows are never roots.
|
|
33
33
|
|
|
34
34
|
Symbol and fill rules:
|
|
35
35
|
- \`e#\` entity; \`m#\` method; \`p#\` field/param/filter; \`r#\` relation nav; \`v#\` value-domain metadata only.
|
|
36
|
-
- Relation hops: \`.
|
|
36
|
+
- Relation hops: \`.r#\` (or the relation wire) on row producers — never a bare filter \`p#\` after \`.\` (\`p#\` in \`e#{…}\` is filter/param).
|
|
37
37
|
- Never write \`v#\` in code; use \`p#\` keys and read \`v#\` rows for allowed values.
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
38
|
+
- **Session handles** (\`logical_session_ref\`, \`run_ref\` / \`pcN\`): MCP tokens only — copy verbatim; not program syntax.
|
|
39
|
+
- Replace teaching placeholders (\`$\`, \`<id>\`, \`<val>\`) and exemplar ids (\`pikachu\`, \`example-name\`, …) with real values before output. Never emit \`$\` from a teaching row.
|
|
40
|
+
- Get-head: **parens = identity** (\`e_type(electric)\`; bare word = string identity when the slot is a name/string field), **braces = query/filter** (\`e#{p#=…}\`). Keyed \`e#(p#=<id>)\` only when that \`p#\` is the identity field.
|
|
41
|
+
- **Quote scalars only in \`{…}\` predicates** (\`e#{p#="EVA"}\`); identity ids in \`e#(…)\` need no quotes. EntityRef slots use \`e#(id)\`, not bare scalars.
|
|
42
|
+
- Remove \`..\` ellipses; add \`opt:\` keys (from \`Meaning\`) only as keyed assignments with real values.
|
|
43
|
+
- Projection \`[p#,…]\` suffixes: reuse only on expressions returning the same entity/list type.
|
|
42
44
|
|
|
43
45
|
Core surface:
|
|
44
46
|
- Program shape: one \`plasm_expr\`, or \`label = …\` bindings then comma-separated final roots (no \`return\`).
|
|
45
|
-
- Postfix
|
|
46
|
-
- Large list reads return the first **25 rows** in \`plasm_run\`;
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
- Search when exposed: \`e#~$\` or \`e#~"text"\` (bare \`e#~\` is invalid); optional scoped filters \`e#~"text"[{p#=…}]\`.
|
|
50
|
-
- Field projection suffix: \`[p#,…]\`.
|
|
47
|
+
- Postfix/\`[p#]\`/\`[fields]\`: copy exact forms from the TSV left column (\`.limit\` \`.sort\` \`.filter{…}\` \`.group_by\` \`.aggregate\` …).
|
|
48
|
+
- Large list reads return the first **25 rows** in \`plasm_run\`; further pages copy the handle from the prior result's "more pages" line into **\`run_ref\`** on the next **\`plasm_run\`** (no second **\`plasm\`** call).
|
|
49
|
+
- \`page(...)\` is HTTP-execute program syntax only — not an MCP tool argument or \`plasm\` program.
|
|
50
|
+
- Search when exposed: \`e#~$\` or \`e#~"text"\` (bare \`e#~\` is a parse error); optional scoped filters \`e#~"text"[{p#=…}]\`.
|
|
51
51
|
|
|
52
52
|
Composition rules:
|
|
53
53
|
- One binding per line; final roots last (preferred). Single-line bindings coerced; default return is first binding.
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
- Pass \`binding.content\` to string params; compose with \`\${report.content}\` in later heredocs/strings (never bare \`\${}\` in prose; \`$$\` escapes \`$\`).
|
|
57
|
-
- Minijinja \`{{ }}\` / \`{% %}\` only inside row-to-text heredoc bodies — not in capability heredocs that use \`\${binding.path}\`.
|
|
58
|
-
- Do not use \`report.content\` as a final root or relation receiver.
|
|
54
|
+
- Row text: \`label = source <<TAG\` … \`TAG\` (equals required); optional \`label = source[p#,…] <<TAG\`. Minijinja \`{{ }}\` / \`{% %}\` over \`rows\` only inside the heredoc body — not \`\${}\`.
|
|
55
|
+
- Pass \`binding.content\` to string params; compose with \`\${report.content}\` in later heredocs/strings (\`$$\` escapes \`$\`). Do not use \`report.content\` as a final root or relation receiver.
|
|
59
56
|
- Action/create roots: return the action row or follow with \`e#(p#=…)\` get — not \`created.p#\` as a program root.
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
- Examples: array argument \`p#=[e#(<id>), …]\`. Quoted strings use only \`\\"\` and \`\\\\\` escapes.
|
|
63
|
-
- Worked row-compute program (shape only — substitute \`e#\` / \`p#\` from your table below):
|
|
57
|
+
- Heredoc: \`<<TAG\` + newline; first trimmed \`TAG\` line closes; pick a tag absent from the body. \`markdown\`/\`html\`/\`document\`/\`json_text\`/\`blob\` values use \`<<TAG\` … \`TAG\` only.
|
|
58
|
+
- Worked shape (substitute symbols from your TSV):
|
|
64
59
|
items = e_source
|
|
65
|
-
filtered = items.filter{p_field>=300}
|
|
66
|
-
sorted = filtered.sort(p_field, desc)
|
|
67
|
-
|
|
68
|
-
limited[p_a,p_field]
|
|
69
|
-
- Worked federated relation + row compute (shape only — copy \`e#\` / \`.r#\` from your table's left column):
|
|
70
|
-
parent = e2(p_key=<val>)
|
|
71
|
-
children = parent.rN
|
|
72
|
-
limited = children.limit(5)
|
|
73
|
-
limited[p_a,p_b]
|
|
74
|
-
- \`markdown\`/\`html\`/\`document\`/\`json_text\`/\`blob\` values (per \`Meaning\`): \`<<TAG\` … \`TAG\` only; e.g. \`e2.mN(..., p#=<<TXT\` + newline body + \`TXT\` newline \`)\`.
|
|
60
|
+
filtered = items.filter{p_field>=300}
|
|
61
|
+
sorted = filtered.sort(p_field, desc).limit(10)
|
|
62
|
+
sorted[p_a,p_field]
|
|
75
63
|
|
|
76
64
|
Common pitfalls:
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
- Homograph: relation fanout via \`.r#\`/wire; \`labels = issues.p#\` forgiven when binding name matches.
|
|
82
|
-
- Never emit \`$\` from teaching rows; substitute real ids and \`e#~"text"\` search terms.
|
|
65
|
+
- Prefer \`label = e#\` then \`label.filter{…}\`; bare \`e#.filter{…}\` list-alls first. Row \`.filter{…}\` needs a materialized list.
|
|
66
|
+
- \`=>\` only for derive \`{ k: _.field }\` or write effects (\`source => e#.m#(…)\`) — not relation reads (use \`child = source.r#\`).
|
|
67
|
+
- Federated writes: one created-row return; discover anchors live — never hardcode workspace ids.
|
|
68
|
+
- **Symbols only:** use this session's \`e#\` / \`m#\` / \`r#\` / \`p#\` from the teaching TSV — not catalog type names, method verbs, or API labels. Unambiguous single-catalog wire names may parse, but always prefer taught \`e#\`/\`m#\`.
|
|
83
69
|
- Search operand: \`e#~$\` or \`e#~"text"\` required — bare \`e#~\` is a parse error.
|
|
84
70
|
- Federated sessions: when the same wire entity/method/relation/field name appears in multiple catalogs, bare wire tokens are compile errors — copy the session \`e#\` / \`m#\` / \`r#\` / \`p#\` from the teaching row for that catalog. Never write \`entry_id:Entity\` or \`catalog.Entity\` in programs.
|
|
85
|
-
- Cross-catalog stitch (shape only — substitute symbols from your TSV): pokeapi \`Type\` get → row-to-text bindings → proof \`ShareLink\` document param with \`\${binding.content}\` inside \`<<TAG\` … \`TAG\`.
|
|
86
71
|
- Search-only entities (no query): no \`e#{}\` list-all — scoped \`e#{p#=…}\` and/or \`e#~"text"\`.`;
|
|
87
72
|
|
|
88
|
-
export const PLASM_RUN_TOOL_DESCRIPTION = `**Run Plasm** (live): **\`logical_session_ref\`** + **\`
|
|
73
|
+
export const PLASM_RUN_TOOL_DESCRIPTION = `**Run Plasm** (live): **\`logical_session_ref\`** + **\`run_ref\`** — a \`pcN\` plan commit from **\`plasm\`**, or the page handle from a prior result's "more pages" line. Real HTTP/API; may return **\`resource_link\`** snapshots.
|
|
89
74
|
|
|
90
|
-
**Review gate:**
|
|
75
|
+
**Review gate:** first live run executes the reviewed plan for the \`pcN\` **\`run_ref\`** from **\`plasm\`**. If the token is missing, expired, or from another plan, call **\`plasm\`** again.
|
|
76
|
+
|
|
77
|
+
**Paging:** when a result says \`more pages — call plasm_run with run_ref: "…"\`, copy that handle into **\`run_ref\`** on the next **\`plasm_run\`** (same **\`logical_session_ref\`**; no second **\`plasm\`** call). \`page(...)\` is HTTP-execute program syntax only — not an MCP tool argument.
|
|
91
78
|
|
|
92
79
|
**Live execute:** server spawns one async operation and awaits terminal rows in the tool response. Progress uses standard \`notifications/plasm/op\` on the registered handle.
|
|
93
80
|
|
|
94
|
-
**Live results:** \`## {return_label} ({n} rows)\` + capped TSV (25 rows inline); multi-return programs use \`# Results\` with \`### {label} ({n} rows)\` per root.
|
|
81
|
+
**Live results:** \`## {return_label} ({n} rows)\` + capped TSV (25 rows inline); multi-return programs use \`# Results\` with \`### {label} ({n} rows)\` per root. ≤25 rows → inline \` \`\`tsv \`\`; 26–499 → capped TSV + snapshot URI (\`resources/read\` when the host supports it); 500+ → preview + snapshot, no inline TSV — narrow the program or page.`;
|
package/src/tools/format.ts
CHANGED
|
@@ -13,8 +13,8 @@ export function formatPlasmContextMarkdown(
|
|
|
13
13
|
return `\`${logicalSessionRef}\`\n\n\`\`\`tsv\n${delta}\n\`\`\`\n`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function formatPlasmDryRunMarkdown(summary: string,
|
|
17
|
-
return `\`\`\`text\n${summary.trim()}\n\`\`\`\n\n**Run:** pass \`
|
|
16
|
+
export function formatPlasmDryRunMarkdown(summary: string, runRef: string): string {
|
|
17
|
+
return `\`\`\`text\n${summary.trim()}\n\`\`\`\n\n**Run:** pass \`run_ref\`: \`${runRef}\` to **\`plasm_run\`**. Do not echo the program.`;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function formatPlasmRunMarkdown(
|
package/src/tools/plasm-tools.ts
CHANGED
|
@@ -62,9 +62,9 @@ const plasmRunInputSchema = z.object({
|
|
|
62
62
|
logical_session_ref: z
|
|
63
63
|
.string()
|
|
64
64
|
.describe("Same logical_session_ref returned by plasm_context"),
|
|
65
|
-
|
|
65
|
+
run_ref: z
|
|
66
66
|
.string()
|
|
67
|
-
.describe("
|
|
67
|
+
.describe("pcN from plasm dry-run, or page handle from a prior plasm_run more-pages line"),
|
|
68
68
|
reasoning: z
|
|
69
69
|
.string()
|
|
70
70
|
.optional()
|
|
@@ -100,10 +100,10 @@ export function createPlasmTools(runtime: AgentRuntime): ToolSet {
|
|
|
100
100
|
plasm_run: tool({
|
|
101
101
|
description: PLASM_RUN_TOOL_DESCRIPTION,
|
|
102
102
|
inputSchema: toolInput(plasmRunInputSchema),
|
|
103
|
-
execute: async ({ logical_session_ref,
|
|
103
|
+
execute: async ({ logical_session_ref, run_ref, reasoning }) =>
|
|
104
104
|
runtime.plasmRun({
|
|
105
105
|
logicalSessionRef: logical_session_ref,
|
|
106
|
-
|
|
106
|
+
runRef: run_ref,
|
|
107
107
|
reasoning,
|
|
108
108
|
}),
|
|
109
109
|
}),
|
|
@@ -19,7 +19,9 @@ export function resolveWorkflowWorldType(
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Bootstrap Workflow SDK world from agent definition.
|
|
22
|
-
* - `vercel`:
|
|
22
|
+
* - `vercel`: Vercel World is selected automatically by the Workflow SDK when
|
|
23
|
+
* `VERCEL_DEPLOYMENT_ID` is set; durable session routes require `/.well-known/workflow/`
|
|
24
|
+
* (eve emits these via Nitro + @workflow/nitro when sources contain `use workflow` / `use step`).
|
|
23
25
|
* - `postgres`: `@workflow/world-postgres` long-lived worker
|
|
24
26
|
* - `local`: `@workflow/world-local` for dev
|
|
25
27
|
*/
|
|
@@ -28,6 +30,15 @@ export async function bootstrapWorkflowWorld(
|
|
|
28
30
|
): Promise<WorkflowWorldType> {
|
|
29
31
|
const worldType = resolveWorkflowWorldType(definition);
|
|
30
32
|
if (worldType === "vercel") {
|
|
33
|
+
if (process.env.VERCEL_DEPLOYMENT_ID?.trim()) {
|
|
34
|
+
try {
|
|
35
|
+
const { getWorld } = await import("workflow/runtime");
|
|
36
|
+
await getWorld().start?.();
|
|
37
|
+
} catch (err) {
|
|
38
|
+
if (process.env.PLASM_WORKFLOW_STRICT === "1") throw err;
|
|
39
|
+
console.warn("[plasm:workflow] vercel world start skipped:", err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
31
42
|
return worldType;
|
|
32
43
|
}
|
|
33
44
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
import { registerOTel } from "@vercel/otel";
|
|
5
|
+
import { OpenTelemetry } from "@ai-sdk/otel";
|
|
6
|
+
import { registerTelemetryIntegration } from "ai";
|
|
7
|
+
|
|
8
|
+
const agentRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const serviceName =
|
|
10
|
+
process.env.PLASM_AGENT_NAME?.trim() || path.basename(path.dirname(agentRoot));
|
|
11
|
+
|
|
12
|
+
/** Eve-shaped OTEL bootstrap — optional export to Braintrust/Datadog via registerOTel. */
|
|
13
|
+
export function register(): void {
|
|
14
|
+
registerOTel({ serviceName });
|
|
15
|
+
registerTelemetryIntegration(new OpenTelemetry());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
register();
|
|
@@ -257,9 +257,16 @@ export function tavilyConfigured(): boolean {
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
export function gatewayConfigured(): boolean {
|
|
260
|
-
|
|
260
|
+
if (
|
|
261
261
|
process.env.AI_GATEWAY_API_KEY?.trim() ||
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
process.env.AI_API_GATEWAY_KEY?.trim() ||
|
|
263
|
+
process.env.AI_GATEWAY_KEY?.trim()
|
|
264
|
+
) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
return (
|
|
268
|
+
process.env.VERCEL === "1" ||
|
|
269
|
+
Boolean(process.env.VERCEL_DEPLOYMENT_ID?.trim()) ||
|
|
270
|
+
Boolean(process.env.VERCEL_ENV?.trim())
|
|
264
271
|
);
|
|
265
272
|
}
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"crons": [
|
|
5
|
-
{
|
|
6
|
-
"path": "/internal/cron/mcp-radar-scan",
|
|
7
|
-
"schedule": "0 */6 * * *"
|
|
8
|
-
}
|
|
9
|
-
],
|
|
10
|
-
"functions": {
|
|
11
|
-
"api/**": {
|
|
12
|
-
"maxDuration": 300
|
|
13
|
-
}
|
|
14
|
-
}
|
|
2
|
+
"installCommand": "npm ci --omit=dev",
|
|
3
|
+
"buildCommand": "plasm-agent build"
|
|
15
4
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
import { registerOTel } from "@vercel/otel";
|
|
5
|
+
import { OpenTelemetry } from "@ai-sdk/otel";
|
|
6
|
+
import { registerTelemetryIntegration } from "ai";
|
|
7
|
+
|
|
8
|
+
const agentRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const serviceName =
|
|
10
|
+
process.env.PLASM_AGENT_NAME?.trim() || path.basename(path.dirname(agentRoot));
|
|
11
|
+
|
|
12
|
+
/** Eve-shaped OTEL bootstrap — optional export to Braintrust/Datadog via registerOTel. */
|
|
13
|
+
export function register(): void {
|
|
14
|
+
registerOTel({ serviceName });
|
|
15
|
+
registerTelemetryIntegration(new OpenTelemetry());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
register();
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"crons": [
|
|
5
|
-
{
|
|
6
|
-
"path": "/internal/cron/mcp-radar-scan",
|
|
7
|
-
"schedule": "0 */6 * * *"
|
|
8
|
-
}
|
|
9
|
-
],
|
|
10
|
-
"functions": {
|
|
11
|
-
"api/**": {
|
|
12
|
-
"maxDuration": 300
|
|
13
|
-
}
|
|
14
|
-
}
|
|
2
|
+
"installCommand": "npm ci --omit=dev",
|
|
3
|
+
"buildCommand": "plasm-agent build"
|
|
15
4
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
|
|
4
|
-
import agentDefinition from "../agent/agent.js";
|
|
5
|
-
import { createPlasmApp, vercelPlasmHandler } from "@plasm_lang/vercel-agent";
|
|
6
|
-
|
|
7
|
-
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
|
-
const agentRoot = path.join(packageRoot, "agent");
|
|
9
|
-
|
|
10
|
-
let app: Awaited<ReturnType<typeof createPlasmApp>> | undefined;
|
|
11
|
-
|
|
12
|
-
export default async function handler(
|
|
13
|
-
req: import("node:http").IncomingMessage,
|
|
14
|
-
res: import("node:http").ServerResponse,
|
|
15
|
-
): Promise<void> {
|
|
16
|
-
app ??= await createPlasmApp({
|
|
17
|
-
agentRoot,
|
|
18
|
-
definition: agentDefinition,
|
|
19
|
-
mode: "prod",
|
|
20
|
-
sessions: false,
|
|
21
|
-
});
|
|
22
|
-
await vercelPlasmHandler(app)(req, res);
|
|
23
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { defineNitroConfig } from "nitropack/config";
|
|
2
|
-
|
|
3
|
-
export default defineNitroConfig({
|
|
4
|
-
compatibilityDate: "2026-06-26",
|
|
5
|
-
srcDir: ".",
|
|
6
|
-
ignore: ["api/**"],
|
|
7
|
-
devServer: {
|
|
8
|
-
port: Number(process.env.PORT ?? 3000),
|
|
9
|
-
host: process.env.HOST ?? "127.0.0.1",
|
|
10
|
-
},
|
|
11
|
-
typescript: {
|
|
12
|
-
strict: false,
|
|
13
|
-
},
|
|
14
|
-
externals: {
|
|
15
|
-
inline: ["@plasm_lang/engine"],
|
|
16
|
-
},
|
|
17
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import { fromNodeMiddleware } from "h3";
|
|
4
|
-
|
|
5
|
-
import agentDefinition from "../agent/agent.js";
|
|
6
|
-
import { createPlasmApp, vercelPlasmHandler } from "@plasm_lang/vercel-agent";
|
|
7
|
-
|
|
8
|
-
const agentRoot = path.join(process.cwd(), "agent");
|
|
9
|
-
|
|
10
|
-
let appPromise: ReturnType<typeof createPlasmApp> | undefined;
|
|
11
|
-
|
|
12
|
-
async function plasmApp() {
|
|
13
|
-
appPromise ??= createPlasmApp({
|
|
14
|
-
agentRoot,
|
|
15
|
-
definition: agentDefinition,
|
|
16
|
-
mode: "prod",
|
|
17
|
-
sessions: false,
|
|
18
|
-
});
|
|
19
|
-
return appPromise;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default fromNodeMiddleware(async (req, res) => {
|
|
23
|
-
const app = await plasmApp();
|
|
24
|
-
await new Promise<void>((resolve, reject) => {
|
|
25
|
-
res.once("finish", () => resolve());
|
|
26
|
-
res.once("error", reject);
|
|
27
|
-
void vercelPlasmHandler(app)(req, res).catch(reject);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
|
|
4
|
-
import agentDefinition from "../agent/agent.js";
|
|
5
|
-
import { createPlasmApp, vercelPlasmHandler } from "@plasm_lang/vercel-agent/server";
|
|
6
|
-
|
|
7
|
-
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
|
-
const agentRoot = path.join(packageRoot, "agent");
|
|
9
|
-
|
|
10
|
-
let app: Awaited<ReturnType<typeof createPlasmApp>> | undefined;
|
|
11
|
-
|
|
12
|
-
export default async function handler(
|
|
13
|
-
req: import("node:http").IncomingMessage,
|
|
14
|
-
res: import("node:http").ServerResponse,
|
|
15
|
-
): Promise<void> {
|
|
16
|
-
app ??= await createPlasmApp({
|
|
17
|
-
agentRoot,
|
|
18
|
-
definition: agentDefinition,
|
|
19
|
-
mode: "prod",
|
|
20
|
-
sessions: false,
|
|
21
|
-
});
|
|
22
|
-
await vercelPlasmHandler(app)(req, res);
|
|
23
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { defineNitroConfig } from "nitropack/config";
|
|
2
|
-
|
|
3
|
-
export default defineNitroConfig({
|
|
4
|
-
compatibilityDate: "2026-06-26",
|
|
5
|
-
srcDir: ".",
|
|
6
|
-
ignore: ["api/**"],
|
|
7
|
-
devServer: {
|
|
8
|
-
port: Number(process.env.PORT ?? 3000),
|
|
9
|
-
host: process.env.HOST ?? "127.0.0.1",
|
|
10
|
-
},
|
|
11
|
-
typescript: {
|
|
12
|
-
strict: false,
|
|
13
|
-
},
|
|
14
|
-
externals: {
|
|
15
|
-
inline: ["@plasm_lang/engine"],
|
|
16
|
-
},
|
|
17
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import { fromNodeMiddleware } from "h3";
|
|
4
|
-
|
|
5
|
-
import agentDefinition from "../agent/agent.js";
|
|
6
|
-
import { createPlasmApp, vercelPlasmHandler } from "@plasm_lang/vercel-agent/server";
|
|
7
|
-
|
|
8
|
-
const agentRoot = path.join(process.cwd(), "agent");
|
|
9
|
-
|
|
10
|
-
let appPromise: ReturnType<typeof createPlasmApp> | undefined;
|
|
11
|
-
|
|
12
|
-
async function plasmApp() {
|
|
13
|
-
appPromise ??= createPlasmApp({
|
|
14
|
-
agentRoot,
|
|
15
|
-
definition: agentDefinition,
|
|
16
|
-
mode: "prod",
|
|
17
|
-
sessions: false,
|
|
18
|
-
});
|
|
19
|
-
return appPromise;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default fromNodeMiddleware(async (req, res) => {
|
|
23
|
-
const app = await plasmApp();
|
|
24
|
-
await new Promise<void>((resolve, reject) => {
|
|
25
|
-
res.once("finish", () => resolve());
|
|
26
|
-
res.once("error", reject);
|
|
27
|
-
void vercelPlasmHandler(app)(req, res).catch(reject);
|
|
28
|
-
});
|
|
29
|
-
});
|