@introspection-ai/recipes 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -58
- package/dist/{agent-tool.d.ts → agents.d.ts} +4 -1
- package/dist/agents.d.ts.map +1 -0
- package/dist/{agent-tool.js → agents.js} +1 -1
- package/dist/agents.js.map +1 -0
- package/dist/api/extensions.d.ts +3 -0
- package/dist/api/extensions.d.ts.map +1 -0
- package/dist/api/extensions.js +2 -0
- package/dist/api/extensions.js.map +1 -0
- package/dist/api/mcp.d.ts +4 -0
- package/dist/api/mcp.d.ts.map +1 -0
- package/dist/api/mcp.js +2 -0
- package/dist/api/mcp.js.map +1 -0
- package/dist/api/session.d.ts +3 -0
- package/dist/api/session.d.ts.map +1 -0
- package/dist/api/session.js +2 -0
- package/dist/api/session.js.map +1 -0
- package/dist/child-agent.d.ts +5 -4
- package/dist/child-agent.d.ts.map +1 -1
- package/dist/child-agent.js +26 -117
- package/dist/child-agent.js.map +1 -1
- package/dist/child-session.d.ts +23 -0
- package/dist/child-session.d.ts.map +1 -0
- package/dist/child-session.js +48 -0
- package/dist/child-session.js.map +1 -0
- package/dist/extensions.d.ts +29 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +119 -0
- package/dist/extensions.js.map +1 -0
- package/dist/index.d.ts +4 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -13
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +38 -5
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +92 -41
- package/dist/inspect.js.map +1 -1
- package/dist/interactions.d.ts +18 -2
- package/dist/interactions.d.ts.map +1 -1
- package/dist/interactions.js +41 -10
- package/dist/interactions.js.map +1 -1
- package/dist/mcp-catalog.d.ts +1 -0
- package/dist/mcp-catalog.d.ts.map +1 -1
- package/dist/mcp-catalog.js +14 -6
- package/dist/mcp-catalog.js.map +1 -1
- package/dist/mcp-chunks/auth-command-ZLGYIEUY.js +273 -0
- package/dist/mcp-chunks/call-arguments-LU3W6D3K.js +13 -0
- package/dist/mcp-chunks/call-command-LKTKSYTH.js +612 -0
- package/dist/mcp-chunks/chunk-2U4BSDC4.js +3951 -0
- package/dist/mcp-chunks/chunk-2XL7MG7R.js +272 -0
- package/dist/mcp-chunks/chunk-3BJA27PY.js +2321 -0
- package/dist/mcp-chunks/chunk-4SQKWYFF.js +15 -0
- package/dist/mcp-chunks/chunk-5QOSCSQB.js +290 -0
- package/dist/mcp-chunks/chunk-6W5QFASN.js +77 -0
- package/dist/mcp-chunks/chunk-6XCZGU3G.js +1004 -0
- package/dist/mcp-chunks/chunk-7FHEBT5G.js +149 -0
- package/dist/mcp-chunks/chunk-7KA2VJVZ.js +114 -0
- package/dist/mcp-chunks/chunk-7UDVSOOF.js +138 -0
- package/dist/mcp-chunks/chunk-BNV3TPE4.js +66 -0
- package/dist/mcp-chunks/chunk-BTLAWHTA.js +129 -0
- package/dist/mcp-chunks/chunk-BV56DXPW.js +13 -0
- package/dist/mcp-chunks/chunk-BWHIA4PC.js +90 -0
- package/dist/mcp-chunks/chunk-BZIQOWE6.js +267 -0
- package/dist/mcp-chunks/chunk-D3MRAZ6H.js +16140 -0
- package/dist/mcp-chunks/chunk-DHBE7UBH.js +750 -0
- package/dist/mcp-chunks/chunk-E22DYOW5.js +251 -0
- package/dist/mcp-chunks/chunk-ECIVB7P4.js +139 -0
- package/dist/mcp-chunks/chunk-HKRJ6O36.js +1076 -0
- package/dist/mcp-chunks/chunk-IABRYROW.js +44 -0
- package/dist/mcp-chunks/chunk-J6LYIZXN.js +45 -0
- package/dist/mcp-chunks/chunk-L7NTQVYN.js +161 -0
- package/dist/mcp-chunks/chunk-LEZSACDE.js +141 -0
- package/dist/mcp-chunks/chunk-LKIBAYKU.js +208 -0
- package/dist/mcp-chunks/chunk-LNH5LAJD.js +152 -0
- package/dist/mcp-chunks/chunk-LQQEYD76.js +124 -0
- package/dist/mcp-chunks/chunk-LRKZP7DJ.js +47 -0
- package/dist/mcp-chunks/chunk-LS7PMWSR.js +109 -0
- package/dist/mcp-chunks/chunk-M3TPODXI.js +95 -0
- package/dist/mcp-chunks/chunk-MZ2NARG7.js +400 -0
- package/dist/mcp-chunks/chunk-N46NEFAF.js +45 -0
- package/dist/mcp-chunks/chunk-NNOEGEUZ.js +17273 -0
- package/dist/mcp-chunks/chunk-NRAJX5E4.js +69 -0
- package/dist/mcp-chunks/chunk-P3PSC54P.js +869 -0
- package/dist/mcp-chunks/chunk-PIIYJR44.js +6341 -0
- package/dist/mcp-chunks/chunk-PWYFKGKG.js +385 -0
- package/dist/mcp-chunks/chunk-SJCCBNZ4.js +45 -0
- package/dist/mcp-chunks/chunk-TATVT5IT.js +194 -0
- package/dist/mcp-chunks/chunk-TEUKFFQL.js +29 -0
- package/dist/mcp-chunks/chunk-UKYNQGNE.js +150 -0
- package/dist/mcp-chunks/chunk-UNKB4SBV.js +37 -0
- package/dist/mcp-chunks/chunk-WD6BOD24.js +138 -0
- package/dist/mcp-chunks/chunk-WQJZMCJN.js +73 -0
- package/dist/mcp-chunks/chunk-XANPGTLI.js +364 -0
- package/dist/mcp-chunks/chunk-XQK2JSW4.js +35 -0
- package/dist/mcp-chunks/chunk-YHQUTU6L.js +571 -0
- package/dist/mcp-chunks/chunk-YVZKMV5H.js +57 -0
- package/dist/mcp-chunks/cli-UV4QJZZM.js +929 -0
- package/dist/mcp-chunks/client-S7RQUG5U.js +13 -0
- package/dist/mcp-chunks/config-command-NLAGKID5.js +1101 -0
- package/dist/mcp-chunks/daemon-command-U242Z6VY.js +26 -0
- package/dist/mcp-chunks/dist-LK3SHAMX.js +6478 -0
- package/dist/mcp-chunks/emit-ts-command-VBXVXO6V.js +386 -0
- package/dist/mcp-chunks/generate-cli-runner-6CAZZA3P.js +1426 -0
- package/dist/mcp-chunks/inspect-cli-command-3ZORTOR7.js +111 -0
- package/dist/mcp-chunks/launch-YKRXHXJI.js +10 -0
- package/dist/mcp-chunks/lifecycle-XVKRHPH3.js +16 -0
- package/dist/mcp-chunks/list-command-2MEGGNFQ.js +4190 -0
- package/dist/mcp-chunks/output-utils-NKESLAJ6.js +12 -0
- package/dist/mcp-chunks/prompt-B1Yc1NPt-VGOTWJMN.js +918 -0
- package/dist/mcp-chunks/record-command-YXHTTTT5.js +17 -0
- package/dist/mcp-chunks/replay-command-25HJ6AQU.js +85 -0
- package/dist/mcp-chunks/resource-command-OO4NYF5C.js +97 -0
- package/dist/mcp-chunks/result-utils-MOHHLNM7.js +15 -0
- package/dist/mcp-chunks/runtime-5WJ3G25Y.js +33 -0
- package/dist/mcp-chunks/runtime-wrapper-RPWDIDBF.js +10 -0
- package/dist/mcp-chunks/serve-command-DHXJZMMN.js +3302 -0
- package/dist/mcp-chunks/timeouts-W2XWCCXR.js +18 -0
- package/dist/mcp-chunks/vault-command-PIYIUEZL.js +154 -0
- package/dist/mcp-daemon-client.d.ts +6 -1
- package/dist/mcp-daemon-client.d.ts.map +1 -1
- package/dist/mcp-daemon-client.js +119 -2
- package/dist/mcp-daemon-client.js.map +1 -1
- package/dist/mcp-daemon-protocol.d.ts +18 -1
- package/dist/mcp-daemon-protocol.d.ts.map +1 -1
- package/dist/mcp-daemon-protocol.js +31 -0
- package/dist/mcp-daemon-protocol.js.map +1 -1
- package/dist/mcp-daemon.js +169 -76602
- package/dist/mcp-daemon.js.map +1 -1
- package/dist/mcp-policy.d.ts +11 -0
- package/dist/mcp-policy.d.ts.map +1 -0
- package/dist/mcp-policy.js +27 -0
- package/dist/mcp-policy.js.map +1 -0
- package/dist/mcp-run-worker.js +38 -76540
- package/dist/mcp-tools.d.ts +39 -0
- package/dist/mcp-tools.d.ts.map +1 -0
- package/dist/mcp-tools.js +493 -0
- package/dist/mcp-tools.js.map +1 -0
- package/dist/mcp.d.ts +21 -9
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +101 -31
- package/dist/mcp.js.map +1 -1
- package/dist/model-binding.d.ts +39 -0
- package/dist/model-binding.d.ts.map +1 -0
- package/dist/model-binding.js +103 -0
- package/dist/model-binding.js.map +1 -0
- package/dist/pi-extension.d.ts +2 -22
- package/dist/pi-extension.d.ts.map +1 -1
- package/dist/pi-extension.js +296 -71
- package/dist/pi-extension.js.map +1 -1
- package/dist/recipe/resolve.d.ts +43 -20
- package/dist/recipe/resolve.d.ts.map +1 -1
- package/dist/recipe/resolve.js +215 -70
- package/dist/recipe/resolve.js.map +1 -1
- package/dist/recipe-agent.d.ts +24 -27
- package/dist/recipe-agent.d.ts.map +1 -1
- package/dist/recipe-agent.js +278 -230
- package/dist/recipe-agent.js.map +1 -1
- package/dist/recipe-check.d.ts +17 -0
- package/dist/recipe-check.d.ts.map +1 -0
- package/dist/recipe-check.js +258 -0
- package/dist/recipe-check.js.map +1 -0
- package/dist/recipe-extensions.d.ts.map +1 -1
- package/dist/recipe-extensions.js +0 -3
- package/dist/recipe-extensions.js.map +1 -1
- package/dist/recipe-model.d.ts +3 -1
- package/dist/recipe-model.d.ts.map +1 -1
- package/dist/recipe-model.js +15 -12
- package/dist/recipe-model.js.map +1 -1
- package/dist/recipe-package.d.ts +6 -28
- package/dist/recipe-package.d.ts.map +1 -1
- package/dist/recipe-package.js +248 -191
- package/dist/recipe-package.js.map +1 -1
- package/dist/recipe-skills.d.ts.map +1 -1
- package/dist/recipe-skills.js +42 -29
- package/dist/recipe-skills.js.map +1 -1
- package/dist/run-controller.d.ts +10 -9
- package/dist/run-controller.d.ts.map +1 -1
- package/dist/run-controller.js +28 -21
- package/dist/run-controller.js.map +1 -1
- package/dist/session.d.ts +40 -53
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +312 -173
- package/dist/session.js.map +1 -1
- package/dist/test-utils.d.ts +7 -7
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +32 -15
- package/dist/test-utils.js.map +1 -1
- package/docs/agent-composition.md +41 -35
- package/docs/host-api.md +201 -0
- package/docs/index.md +8 -14
- package/docs/interactions.md +12 -11
- package/docs/mcp-auth.md +6 -6
- package/docs/mcp-configuration.md +72 -24
- package/docs/pi-extension.md +39 -11
- package/docs/recipe-flow.md +9 -9
- package/docs/recipe-format.md +90 -41
- package/package.json +23 -17
- package/vendor/mcp-client/darwin-arm64/mcp-client +0 -0
- package/vendor/mcp-client/darwin-x64/mcp-client +0 -0
- package/vendor/mcp-client/linux-arm64/mcp-client +0 -0
- package/vendor/recipe-check/darwin-arm64/recipe-check +0 -0
- package/vendor/recipe-check/darwin-x64/recipe-check +0 -0
- package/vendor/recipe-check/linux-arm64/recipe-check +0 -0
- package/vendor/recipe-check/linux-x64/recipe-check +0 -0
- package/vendor/recipe-check/linux-x64-musl/recipe-check +0 -0
- package/vendor/recipe-check/win32-x64/recipe-check.exe +0 -0
- package/dist/agent-tool.d.ts.map +0 -1
- package/dist/agent-tool.js.map +0 -1
- package/dist/run.d.ts +0 -28
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js +0 -84
- package/dist/run.js.map +0 -1
- package/dist/testing.d.ts +0 -25
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -96
- package/dist/testing.js.map +0 -1
- package/docs/deployment-configuration.md +0 -65
- package/docs/migration.md +0 -70
- package/docs/python-bindings-release.md +0 -47
- package/docs/recipe-evals.md +0 -70
- package/docs/recipe-judges.md +0 -152
- package/docs/runtime-library.md +0 -171
package/dist/pi-extension.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { rm } from "node:fs/promises";
|
|
3
4
|
import { basename, resolve } from "node:path";
|
|
4
5
|
import { Text } from "@earendil-works/pi-tui";
|
|
5
6
|
import { createRecipeChildAgentRunner, promptResultText, } from "./child-agent.js";
|
|
6
7
|
import { loadRecipeExtensionFactory } from "./recipe-extensions.js";
|
|
8
|
+
import { bindRecipeExtensionFactory, createRecipeExtensionRegistrationRegistry, } from "./extensions.js";
|
|
7
9
|
import { ChildAgentRunStore, } from "./child-agent-store.js";
|
|
8
10
|
import { ChildCompletionQueue, envelopeFromRun, renderCompletionNotice, } from "./child-agent-completions.js";
|
|
9
|
-
import { clearMcpSession, configureMcpLocalConfigPath, formatMcpConfigurationDiagnostics, materializeMcpSession, materializeSessionMcpCli, resolveAgentMcpSelections, stopMcpDaemon, } from "./mcp.js";
|
|
11
|
+
import { clearMcpSession, clearSessionMcpCli, configureMcpLocalConfigPath, createIsolatedMcpEnvironment, formatMcpConfigurationDiagnostics, materializeMcpSession, materializeSessionMcpCli, resolveAgentMcpSelections, stopMcpDaemon, } from "./mcp.js";
|
|
10
12
|
import { clearMcpCatalogPreload, preloadMcpCatalogs, } from "./mcp-catalog.js";
|
|
11
|
-
import {
|
|
13
|
+
import { createMcpToolSet } from "./mcp-tools.js";
|
|
14
|
+
import { applyRecipeAgentModelConfigToModel, cloneModelForRecipe, } from "./recipe-model.js";
|
|
15
|
+
import { checkRecipeAtLoad, formatRecipeDiagnostics, } from "./recipe-check.js";
|
|
12
16
|
import { resolveRecipe, } from "./recipe/resolve.js";
|
|
13
|
-
import { createAgentTool, } from "./
|
|
17
|
+
import { createAgentTool, } from "./agents.js";
|
|
14
18
|
/** Mid-turn completion delivery retries on this cadence until the session idles. */
|
|
15
19
|
const COMPLETION_DELIVERY_RETRY_MS = 100;
|
|
16
20
|
const require = createRequire(import.meta.url);
|
|
@@ -53,8 +57,8 @@ function visibleSubagents(state) {
|
|
|
53
57
|
function mcpSelectionsForAgent(agent) {
|
|
54
58
|
return resolveAgentMcpSelections(agent.mcp);
|
|
55
59
|
}
|
|
56
|
-
function
|
|
57
|
-
return
|
|
60
|
+
function resolvedMcpMode(state) {
|
|
61
|
+
return state.resolved.mcp?.mode ?? "cli";
|
|
58
62
|
}
|
|
59
63
|
function textResult(text, details) {
|
|
60
64
|
return {
|
|
@@ -102,7 +106,7 @@ function formatAgentCall(args, theme) {
|
|
|
102
106
|
const label = args.label ? ` ${themeFg(theme, "muted", `(${args.label})`)}` : "";
|
|
103
107
|
return `${themeFg(theme, "toolTitle", themeBold(theme, `agent ${action}`))} ${themeFg(theme, "accent", agent)}${label}`;
|
|
104
108
|
}
|
|
105
|
-
//
|
|
109
|
+
// Stable wire value used by persisted transcripts and the renderer.
|
|
106
110
|
const AGENT_COMPLETIONS_TYPE = "recipe-agent-completions";
|
|
107
111
|
function formatDurationMs(ms) {
|
|
108
112
|
const seconds = Math.round(ms / 1000);
|
|
@@ -196,7 +200,10 @@ function bulletList(items) {
|
|
|
196
200
|
}
|
|
197
201
|
function activeRecipeTools(state, activeTools) {
|
|
198
202
|
const active = new Set(activeTools);
|
|
199
|
-
const recipeTools = new Set(
|
|
203
|
+
const recipeTools = new Set([
|
|
204
|
+
...state.resolved.tools,
|
|
205
|
+
...(state.resolved.subagents.size > 0 ? ["agent"] : []),
|
|
206
|
+
]);
|
|
200
207
|
return [...recipeTools]
|
|
201
208
|
.filter((tool) => active.has(tool))
|
|
202
209
|
.sort();
|
|
@@ -207,14 +214,18 @@ function recipeSummary(state, activeTools) {
|
|
|
207
214
|
"Active Recipe",
|
|
208
215
|
`Name: ${state.resolved.manifest.name}@${state.resolved.manifest.version}`,
|
|
209
216
|
state.resolved.manifest.description ? `Description: ${state.resolved.manifest.description}` : undefined,
|
|
210
|
-
`Agent: ${state.resolved.
|
|
211
|
-
`Model: ${state.resolved.
|
|
212
|
-
`Thinking level: ${state.resolved.
|
|
217
|
+
`Agent: ${state.resolved.name}`,
|
|
218
|
+
`Model: ${state.resolved.definition.model?.name ?? "(session default)"}`,
|
|
219
|
+
`Thinking level: ${state.resolved.definition.model?.thinkingLevel ?? "(session default)"}`,
|
|
213
220
|
`Subagents: ${nameList(subagents)}`,
|
|
214
221
|
"",
|
|
215
222
|
"Active recipe tools:",
|
|
216
223
|
...bulletList(activeRecipeTools(state, activeTools)),
|
|
217
224
|
"",
|
|
225
|
+
`Package extensions: ${state.resolved.extensionPaths.length}`,
|
|
226
|
+
`Package prompts: ${state.resolved.promptPaths.length}`,
|
|
227
|
+
"Host layer: trusted ambient Pi hooks and settings may also apply",
|
|
228
|
+
"",
|
|
218
229
|
`Directory: ${state.resolved.recipeDir}`,
|
|
219
230
|
`Workspace: ${state.cwd}`,
|
|
220
231
|
].filter((line) => line !== undefined).join("\n");
|
|
@@ -414,10 +425,32 @@ export function createRecipesExtension(opts = {}) {
|
|
|
414
425
|
childRuns.delete(id);
|
|
415
426
|
return controllerSummary(run, "closed");
|
|
416
427
|
},
|
|
428
|
+
async shutdown() {
|
|
429
|
+
await closeAllChildRuns();
|
|
430
|
+
},
|
|
417
431
|
};
|
|
418
432
|
async function closeAllChildRuns() {
|
|
419
433
|
await Promise.all([...childRuns.keys()].map((id) => localRunController.close(id)));
|
|
420
434
|
}
|
|
435
|
+
async function closeRootMcpRuntime() {
|
|
436
|
+
const privateEnv = state?.mcpPrivateEnv;
|
|
437
|
+
const privateDirectory = state?.mcpPrivateDirectory;
|
|
438
|
+
if (privateEnv) {
|
|
439
|
+
clearMcpCatalogPreload(privateEnv);
|
|
440
|
+
await stopMcpDaemon(privateEnv);
|
|
441
|
+
}
|
|
442
|
+
if (privateDirectory) {
|
|
443
|
+
await rm(privateDirectory, { recursive: true, force: true });
|
|
444
|
+
}
|
|
445
|
+
if (state) {
|
|
446
|
+
state.mcpPrivateEnv = undefined;
|
|
447
|
+
state.mcpPrivateDirectory = undefined;
|
|
448
|
+
if (state.mcpAmbientMcporterConfig) {
|
|
449
|
+
env.MCPORTER_CONFIG = state.mcpAmbientMcporterConfig;
|
|
450
|
+
state.mcpAmbientMcporterConfig = undefined;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
421
454
|
function archivedControlError(id) {
|
|
422
455
|
return {
|
|
423
456
|
...textResult(`Agent run ${id} belongs to a previous Pi session and cannot be controlled; only status and wait are available.`, { id }),
|
|
@@ -429,6 +462,8 @@ export function createRecipesExtension(opts = {}) {
|
|
|
429
462
|
// later session load in the same process.
|
|
430
463
|
const launchRecipeDir = stringFlag(env.PI_RECIPE_DIR);
|
|
431
464
|
const launchAgentName = stringFlag(env.PI_AGENT_NAME);
|
|
465
|
+
const originalRecipeDirEnv = env.PI_RECIPE_DIR;
|
|
466
|
+
const originalAgentNameEnv = env.PI_AGENT_NAME;
|
|
432
467
|
function recipeFlag(pi) {
|
|
433
468
|
return stringFlag(pi.getFlag("recipe")) ?? launchRecipeDir;
|
|
434
469
|
}
|
|
@@ -447,12 +482,11 @@ export function createRecipesExtension(opts = {}) {
|
|
|
447
482
|
const key = [cwd, recipeDir, requestedAgentName ?? ""].join("\0");
|
|
448
483
|
if (state?.key === key)
|
|
449
484
|
return state;
|
|
485
|
+
let resolvedRecipe;
|
|
450
486
|
let resolved;
|
|
451
487
|
try {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
agentName: requestedAgentName,
|
|
455
|
-
});
|
|
488
|
+
resolvedRecipe = resolveRecipe({ recipeDir });
|
|
489
|
+
resolved = resolvedRecipe.selectAgent(requestedAgentName);
|
|
456
490
|
}
|
|
457
491
|
catch (err) {
|
|
458
492
|
throw new RecipeLaunchError(recipeLoadErrorMessage(flag, err instanceof Error ? err.message : String(err)));
|
|
@@ -461,13 +495,22 @@ export function createRecipesExtension(opts = {}) {
|
|
|
461
495
|
// recipe-authored instructions. In production `env` is process.env, so
|
|
462
496
|
// built-in shell tools and child agents inherit these resolved values.
|
|
463
497
|
env.PI_RECIPE_DIR = recipeDir;
|
|
464
|
-
env.PI_AGENT_NAME = resolved.
|
|
498
|
+
env.PI_AGENT_NAME = resolved.name;
|
|
465
499
|
state = {
|
|
466
500
|
key,
|
|
467
501
|
cwd,
|
|
502
|
+
resolvedRecipe,
|
|
468
503
|
resolved,
|
|
504
|
+
extensionRegistrations: createRecipeExtensionRegistrationRegistry(),
|
|
469
505
|
extensionsLoaded: false,
|
|
470
506
|
configured: false,
|
|
507
|
+
mcpConfigured: false,
|
|
508
|
+
agentMcpMode: "cli",
|
|
509
|
+
initialMcpToolNames: [],
|
|
510
|
+
extensionAllowedToolNames: new Set([
|
|
511
|
+
...resolved.tools,
|
|
512
|
+
...(resolved.subagents.size > 0 ? ["agent"] : []),
|
|
513
|
+
]),
|
|
471
514
|
};
|
|
472
515
|
return state;
|
|
473
516
|
}
|
|
@@ -479,29 +522,57 @@ export function createRecipesExtension(opts = {}) {
|
|
|
479
522
|
if (!(err instanceof RecipeLaunchError))
|
|
480
523
|
throw err;
|
|
481
524
|
const key = [cwd, recipeFlag(pi) ?? "", err.message].join("\0");
|
|
482
|
-
if (
|
|
483
|
-
|
|
525
|
+
if (lastLaunchErrorKey !== key) {
|
|
526
|
+
failRecipeSession(pi, err.message, ctx);
|
|
484
527
|
lastLaunchErrorKey = key;
|
|
485
528
|
}
|
|
529
|
+
else {
|
|
530
|
+
sessionConfigurationError = err.message;
|
|
531
|
+
pi.setActiveTools([]);
|
|
532
|
+
}
|
|
486
533
|
return null;
|
|
487
534
|
}
|
|
488
535
|
}
|
|
536
|
+
function failRecipeSession(pi, message, ctx) {
|
|
537
|
+
sessionConfigurationError = message;
|
|
538
|
+
pi.setActiveTools([]);
|
|
539
|
+
ctx?.ui.notify(`Recipe session cannot start: ${message}`, "warning");
|
|
540
|
+
if (ctx?.mode === "json" || ctx?.mode === "print") {
|
|
541
|
+
process.exitCode = 1;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
489
544
|
async function loadRecipeExtensions(pi, ctx, launchState) {
|
|
545
|
+
if (launchState.extensionFailure) {
|
|
546
|
+
throw new Error(launchState.extensionFailure);
|
|
547
|
+
}
|
|
490
548
|
if (launchState.extensionsLoaded)
|
|
491
549
|
return;
|
|
550
|
+
// Pi cannot unload registrations made by an earlier factory if a later
|
|
551
|
+
// factory fails. Mark the closure attempted before execution so the same
|
|
552
|
+
// live runner never retries a partially installed closure.
|
|
553
|
+
launchState.extensionsLoaded = true;
|
|
554
|
+
for (const tool of pi.getAllTools()) {
|
|
555
|
+
launchState.extensionRegistrations.claim("tool", tool.name, "<host>");
|
|
556
|
+
}
|
|
492
557
|
let loadedCount = 0;
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const factory = await loadRecipeExtensionFactory(launchState.resolved.recipeDir, extensionPath)
|
|
558
|
+
try {
|
|
559
|
+
for (const extensionPath of launchState.resolved.extensionPaths) {
|
|
560
|
+
const factory = bindRecipeExtensionFactory(await loadRecipeExtensionFactory(launchState.resolved.recipeDir, extensionPath), Object.freeze({
|
|
561
|
+
recipe: Object.freeze({ name: launchState.resolved.manifest.name }),
|
|
562
|
+
agent: Object.freeze({ name: launchState.resolved.name }),
|
|
563
|
+
session: Object.freeze({
|
|
564
|
+
role: "root",
|
|
565
|
+
}),
|
|
566
|
+
}), launchState.extensionRegistrations, extensionPath, launchState.extensionAllowedToolNames);
|
|
496
567
|
await factory(pi);
|
|
497
568
|
loadedCount += 1;
|
|
498
569
|
}
|
|
499
|
-
catch (err) {
|
|
500
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
501
|
-
ctx.ui.notify(`Recipe extension failed to load: ${extensionPath}\n${message}`, "warning");
|
|
502
|
-
}
|
|
503
570
|
}
|
|
504
|
-
|
|
571
|
+
catch (error) {
|
|
572
|
+
launchState.extensionFailure =
|
|
573
|
+
error instanceof Error ? error.message : String(error);
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
505
576
|
if (launchState.resolved.extensionPaths.length > 0) {
|
|
506
577
|
ctx.ui.notify(`Recipe extensions: ${loadedCount}/${launchState.resolved.extensionPaths.length} loaded`, "info");
|
|
507
578
|
}
|
|
@@ -511,15 +582,16 @@ export function createRecipesExtension(opts = {}) {
|
|
|
511
582
|
return;
|
|
512
583
|
const labelParts = [
|
|
513
584
|
`${launchState.resolved.manifest.name}@${launchState.resolved.manifest.version}`,
|
|
514
|
-
`agent:${launchState.resolved.
|
|
585
|
+
`agent:${launchState.resolved.name}`,
|
|
515
586
|
].filter(Boolean);
|
|
516
587
|
pi.setSessionName(labelParts.join(" "));
|
|
517
588
|
const { provider, model } = modelParts(launchState.resolved.modelSpec);
|
|
518
589
|
const lookupProvider = provider === "gemini" ? "google" : provider;
|
|
519
|
-
const
|
|
520
|
-
if (!
|
|
590
|
+
const registeredModel = ctx.modelRegistry.find(lookupProvider, model);
|
|
591
|
+
if (!registeredModel) {
|
|
521
592
|
throw new Error(`Recipe model is not available: ${launchState.resolved.modelSpec}`);
|
|
522
593
|
}
|
|
594
|
+
const resolvedModel = cloneModelForRecipe(registeredModel);
|
|
523
595
|
applyRecipeAgentModelConfigToModel(resolvedModel, launchState.resolved.modelConfig);
|
|
524
596
|
const ok = await pi.setModel(resolvedModel);
|
|
525
597
|
if (!ok) {
|
|
@@ -528,54 +600,167 @@ export function createRecipesExtension(opts = {}) {
|
|
|
528
600
|
if (launchState.resolved.thinkingLevel) {
|
|
529
601
|
pi.setThinkingLevel(launchState.resolved.thinkingLevel);
|
|
530
602
|
}
|
|
531
|
-
const activeTools = new Set(
|
|
603
|
+
const activeTools = new Set([
|
|
604
|
+
...launchState.resolved.tools,
|
|
605
|
+
...(launchState.resolved.subagents.size > 0 ? ["agent"] : []),
|
|
606
|
+
...launchState.initialMcpToolNames,
|
|
607
|
+
...(launchState.mcpSearchToolName
|
|
608
|
+
? [launchState.mcpSearchToolName]
|
|
609
|
+
: []),
|
|
610
|
+
]);
|
|
611
|
+
const registeredTools = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
612
|
+
const missingTools = [...activeTools].filter((name) => !registeredTools.has(name));
|
|
613
|
+
if (missingTools.length > 0) {
|
|
614
|
+
throw new Error(`Recipe agent "${launchState.resolved.name}" declares unavailable tool(s): ${missingTools.join(", ")}`);
|
|
615
|
+
}
|
|
532
616
|
pi.setActiveTools([...activeTools]);
|
|
533
617
|
launchState.configured = true;
|
|
534
618
|
sessionConfigurationError = null;
|
|
535
619
|
}
|
|
536
|
-
async function configureMcp(launchState, ctx) {
|
|
537
|
-
|
|
538
|
-
if (mcpSelections.length === 0) {
|
|
539
|
-
await clearMcpSession(env, launchState.cwd);
|
|
620
|
+
async function configureMcp(pi, launchState, ctx) {
|
|
621
|
+
if (launchState.mcpConfigured)
|
|
540
622
|
return;
|
|
541
|
-
|
|
623
|
+
launchState.agentMcpMode = resolvedMcpMode(launchState);
|
|
624
|
+
launchState.initialMcpToolNames = [];
|
|
625
|
+
launchState.mcpSearchToolName = undefined;
|
|
542
626
|
configureMcpLocalConfigPath({
|
|
543
627
|
cwd: launchState.cwd,
|
|
544
628
|
recipeDir: launchState.resolved.recipeDir,
|
|
545
629
|
env,
|
|
546
630
|
});
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
env,
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
631
|
+
if (launchState.agentMcpMode === "cli") {
|
|
632
|
+
const mcpSelections = resolveAgentMcpSelections(launchState.resolved.mcp);
|
|
633
|
+
if (mcpSelections.length === 0) {
|
|
634
|
+
await clearMcpSession(env, launchState.cwd);
|
|
635
|
+
launchState.mcpConfigured = true;
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const [, session] = await Promise.all([
|
|
639
|
+
materializeSessionMcpCli({
|
|
640
|
+
cwd: launchState.cwd,
|
|
641
|
+
env,
|
|
642
|
+
}),
|
|
643
|
+
materializeMcpSession({
|
|
644
|
+
cwd: launchState.cwd,
|
|
645
|
+
manifest: launchState.resolved.manifest,
|
|
646
|
+
agentMcp: mcpSelections,
|
|
647
|
+
env,
|
|
648
|
+
}),
|
|
649
|
+
]);
|
|
650
|
+
if (session.servers.length > 0) {
|
|
651
|
+
void preloadMcpCatalogs({ env }).catch((error) => {
|
|
652
|
+
console.warn(`Recipe MCP catalog preload failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
653
|
+
});
|
|
654
|
+
ctx.ui.notify(`Recipe MCP: ${session.servers.length} server(s) configured; runtime warming in background`, "info");
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
const detail = formatMcpConfigurationDiagnostics(session.diagnostics ?? []);
|
|
658
|
+
ctx.ui.notify([
|
|
659
|
+
"Recipe MCP: no servers are available to this agent. Check package policy and .pi/mcp.local.json.",
|
|
660
|
+
...(detail ? ["", detail] : []),
|
|
661
|
+
].join("\n"), "warning");
|
|
662
|
+
}
|
|
564
663
|
const detail = formatMcpConfigurationDiagnostics(session.diagnostics ?? []);
|
|
565
|
-
if (detail) {
|
|
664
|
+
if (session.servers.length > 0 && detail) {
|
|
566
665
|
ctx.ui.notify([
|
|
567
666
|
"Recipe MCP: some configured servers or tools were filtered.",
|
|
568
667
|
"",
|
|
569
668
|
detail,
|
|
570
669
|
].join("\n"), "warning");
|
|
571
670
|
}
|
|
671
|
+
launchState.mcpConfigured = true;
|
|
672
|
+
return;
|
|
572
673
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
674
|
+
const clearedCli = await clearSessionMcpCli(env, launchState.cwd);
|
|
675
|
+
launchState.mcpAmbientMcporterConfig =
|
|
676
|
+
clearedCli.previousMcporterConfig;
|
|
677
|
+
const rootMcp = launchState.resolved.mcp;
|
|
678
|
+
const rootSelections = mcpSelectionsForAgent(launchState.resolved.definition);
|
|
679
|
+
if (!rootMcp || rootSelections.length === 0) {
|
|
680
|
+
launchState.mcpConfigured = true;
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const privateRuntime = await createIsolatedMcpEnvironment(env);
|
|
684
|
+
launchState.mcpPrivateEnv = privateRuntime.env;
|
|
685
|
+
launchState.mcpPrivateDirectory = privateRuntime.directory;
|
|
686
|
+
try {
|
|
687
|
+
const session = await materializeMcpSession({
|
|
688
|
+
cwd: launchState.cwd,
|
|
689
|
+
manifest: launchState.resolved.manifest,
|
|
690
|
+
agentMcp: rootSelections,
|
|
691
|
+
env: privateRuntime.env,
|
|
692
|
+
mcporterConfigPath: privateRuntime.mcporterConfigPath,
|
|
693
|
+
});
|
|
694
|
+
if (session.servers.length === 0) {
|
|
695
|
+
const detail = formatMcpConfigurationDiagnostics(session.diagnostics ?? []);
|
|
696
|
+
ctx.ui.notify([
|
|
697
|
+
"Recipe MCP tools: no servers are available to the root agent.",
|
|
698
|
+
...(detail ? ["", detail] : []),
|
|
699
|
+
].join("\n"), "warning");
|
|
700
|
+
launchState.mcpConfigured = true;
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const catalogs = await preloadMcpCatalogs({
|
|
704
|
+
env: privateRuntime.env,
|
|
705
|
+
allowPartial: true,
|
|
706
|
+
});
|
|
707
|
+
const materialized = createMcpToolSet({
|
|
708
|
+
session,
|
|
709
|
+
catalogs,
|
|
710
|
+
mcp: rootMcp,
|
|
711
|
+
env: privateRuntime.env,
|
|
712
|
+
activation: {
|
|
713
|
+
getActiveTools: () => pi.getActiveTools(),
|
|
714
|
+
setActiveTools: (names) => pi.setActiveTools(names),
|
|
715
|
+
},
|
|
716
|
+
});
|
|
717
|
+
const existing = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
718
|
+
for (const tool of materialized.tools) {
|
|
719
|
+
if (existing.has(tool.name)) {
|
|
720
|
+
throw new Error(`Cannot register MCP tool '${tool.name}': the Pi tool name is already in use.`);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
for (const tool of materialized.tools)
|
|
724
|
+
pi.registerTool(tool);
|
|
725
|
+
const registered = new Set(pi.getAllTools().map((tool) => tool.name));
|
|
726
|
+
const missing = materialized.tools
|
|
727
|
+
.map((tool) => tool.name)
|
|
728
|
+
.filter((name) => !registered.has(name));
|
|
729
|
+
if (missing.length > 0) {
|
|
730
|
+
throw new Error(`Pi did not register MCP tool(s): ${missing.join(", ")}`);
|
|
731
|
+
}
|
|
732
|
+
launchState.initialMcpToolNames =
|
|
733
|
+
materialized.initialActiveToolNames;
|
|
734
|
+
launchState.mcpSearchToolName = materialized.searchToolName;
|
|
735
|
+
for (const toolName of materialized.toolNames) {
|
|
736
|
+
launchState.extensionAllowedToolNames.add(toolName);
|
|
737
|
+
}
|
|
738
|
+
if (materialized.searchToolName) {
|
|
739
|
+
launchState.extensionAllowedToolNames.add(materialized.searchToolName);
|
|
740
|
+
}
|
|
741
|
+
ctx.ui.notify(`Recipe MCP tools: ${materialized.toolNames.length} registered, ${materialized.initialActiveToolNames.length} initially active${materialized.searchToolName ? "; deferred search enabled" : ""}`, "info");
|
|
742
|
+
const diagnostics = [
|
|
743
|
+
...formatMcpConfigurationDiagnostics(session.diagnostics ?? [])
|
|
744
|
+
.split("\n")
|
|
745
|
+
.filter(Boolean),
|
|
746
|
+
...materialized.diagnostics,
|
|
747
|
+
];
|
|
748
|
+
if (diagnostics.length > 0) {
|
|
749
|
+
ctx.ui.notify([
|
|
750
|
+
"Recipe MCP: some configured tools were unavailable.",
|
|
751
|
+
"",
|
|
752
|
+
...diagnostics,
|
|
753
|
+
].join("\n"), "warning");
|
|
754
|
+
}
|
|
755
|
+
launchState.mcpConfigured = true;
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
clearMcpCatalogPreload(privateRuntime.env);
|
|
759
|
+
await stopMcpDaemon(privateRuntime.env);
|
|
760
|
+
await rm(privateRuntime.directory, { recursive: true, force: true });
|
|
761
|
+
launchState.mcpPrivateEnv = undefined;
|
|
762
|
+
launchState.mcpPrivateDirectory = undefined;
|
|
763
|
+
throw error;
|
|
579
764
|
}
|
|
580
765
|
}
|
|
581
766
|
async function runChildAgent(launchState, agentName, prompt, label, ctx, onUpdate) {
|
|
@@ -593,7 +778,7 @@ export function createRecipesExtension(opts = {}) {
|
|
|
593
778
|
}
|
|
594
779
|
};
|
|
595
780
|
const runner = createChildAgentRunner({
|
|
596
|
-
|
|
781
|
+
recipe: launchState.resolvedRecipe,
|
|
597
782
|
workspaceDir: launchState.cwd,
|
|
598
783
|
env,
|
|
599
784
|
agentName,
|
|
@@ -763,6 +948,7 @@ export function createRecipesExtension(opts = {}) {
|
|
|
763
948
|
return;
|
|
764
949
|
}
|
|
765
950
|
await closeAllChildRuns();
|
|
951
|
+
await closeRootMcpRuntime();
|
|
766
952
|
state = null;
|
|
767
953
|
archivedRuns.clear();
|
|
768
954
|
completions.clear();
|
|
@@ -798,37 +984,65 @@ export function createRecipesExtension(opts = {}) {
|
|
|
798
984
|
pi.on("session_start", async (_event, ctx) => {
|
|
799
985
|
sessionCtx = ctx;
|
|
800
986
|
localAgentContext = ctx;
|
|
987
|
+
const selectedRecipe = recipeFlag(pi);
|
|
988
|
+
if (selectedRecipe) {
|
|
989
|
+
const recipeDir = resolve(ctx.cwd, selectedRecipe);
|
|
990
|
+
if (existsSync(recipeDir)) {
|
|
991
|
+
try {
|
|
992
|
+
const report = await checkRecipeAtLoad(recipeDir, env);
|
|
993
|
+
if (!report.valid) {
|
|
994
|
+
const message = formatRecipeDiagnostics(report.diagnostics);
|
|
995
|
+
failRecipeSession(pi, `validation failed\n${message}`, ctx);
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
catch (error) {
|
|
1000
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1001
|
+
failRecipeSession(pi, `validation failed\n${message}`, ctx);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
801
1006
|
const launchState = safeLoadState(pi, ctx.cwd, ctx);
|
|
802
1007
|
if (!launchState)
|
|
803
1008
|
return;
|
|
1009
|
+
launchState.configured = false;
|
|
804
1010
|
visibleAgentDefinitions.clear();
|
|
805
1011
|
for (const [name, definition] of launchState.resolved.subagents) {
|
|
806
1012
|
visibleAgentDefinitions.set(name, definition);
|
|
807
1013
|
}
|
|
808
|
-
await loadRecipeExtensions(pi, ctx, launchState);
|
|
809
1014
|
try {
|
|
810
|
-
await
|
|
1015
|
+
await loadRecipeExtensions(pi, ctx, launchState);
|
|
811
1016
|
}
|
|
812
1017
|
catch (err) {
|
|
813
|
-
|
|
1018
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1019
|
+
failRecipeSession(pi, `extension startup failed\n${message}`, ctx);
|
|
814
1020
|
return;
|
|
815
1021
|
}
|
|
816
1022
|
try {
|
|
817
|
-
await
|
|
1023
|
+
await configureMcp(pi, launchState, ctx);
|
|
818
1024
|
}
|
|
819
1025
|
catch (err) {
|
|
820
1026
|
const message = err instanceof Error ? err.message : String(err);
|
|
821
|
-
// A recipe's declared model is part of its behavior contract. Continuing
|
|
822
|
-
// with Pi's previously active model can produce plausible but invalid
|
|
823
|
-
// results, so stop the session instead of silently falling back.
|
|
824
1027
|
sessionConfigurationError = message;
|
|
825
1028
|
pi.setActiveTools([]);
|
|
826
|
-
ctx.ui.notify(`Recipe
|
|
1029
|
+
ctx.ui.notify(`Recipe MCP failed to configure: ${message}`, "warning");
|
|
827
1030
|
if (ctx.mode === "json" || ctx.mode === "print") {
|
|
828
1031
|
process.exitCode = 1;
|
|
829
1032
|
}
|
|
830
1033
|
return;
|
|
831
1034
|
}
|
|
1035
|
+
try {
|
|
1036
|
+
await configureSession(pi, ctx, launchState);
|
|
1037
|
+
}
|
|
1038
|
+
catch (err) {
|
|
1039
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1040
|
+
// A recipe's declared model is part of its behavior contract. Continuing
|
|
1041
|
+
// with Pi's previously active model can produce plausible but invalid
|
|
1042
|
+
// results, so stop the session instead of silently falling back.
|
|
1043
|
+
failRecipeSession(pi, message, ctx);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
832
1046
|
// Restore run snapshots persisted by a previous Pi process so run ids
|
|
833
1047
|
// referenced in a resumed conversation stay resolvable (read-only).
|
|
834
1048
|
try {
|
|
@@ -844,8 +1058,21 @@ export function createRecipesExtension(opts = {}) {
|
|
|
844
1058
|
});
|
|
845
1059
|
pi.on("session_shutdown", async () => {
|
|
846
1060
|
await closeAllChildRuns();
|
|
1061
|
+
await closeRootMcpRuntime();
|
|
847
1062
|
clearMcpCatalogPreload(env);
|
|
848
1063
|
await stopMcpDaemon(env);
|
|
1064
|
+
if (originalRecipeDirEnv === undefined) {
|
|
1065
|
+
delete env.PI_RECIPE_DIR;
|
|
1066
|
+
}
|
|
1067
|
+
else {
|
|
1068
|
+
env.PI_RECIPE_DIR = originalRecipeDirEnv;
|
|
1069
|
+
}
|
|
1070
|
+
if (originalAgentNameEnv === undefined) {
|
|
1071
|
+
delete env.PI_AGENT_NAME;
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
env.PI_AGENT_NAME = originalAgentNameEnv;
|
|
1075
|
+
}
|
|
849
1076
|
});
|
|
850
1077
|
pi.on("agent_start", (_event, ctx) => {
|
|
851
1078
|
if (!sessionConfigurationError)
|
|
@@ -860,8 +1087,8 @@ export function createRecipesExtension(opts = {}) {
|
|
|
860
1087
|
if (!launchState)
|
|
861
1088
|
return {};
|
|
862
1089
|
return {
|
|
863
|
-
skillPaths: launchState.resolved.skillPaths,
|
|
864
|
-
promptPaths: launchState.resolved.promptPaths,
|
|
1090
|
+
skillPaths: [...launchState.resolved.skillPaths],
|
|
1091
|
+
promptPaths: [...launchState.resolved.promptPaths],
|
|
865
1092
|
};
|
|
866
1093
|
});
|
|
867
1094
|
pi.on("before_agent_start", (event, ctx) => {
|
|
@@ -874,7 +1101,5 @@ export function createRecipesExtension(opts = {}) {
|
|
|
874
1101
|
});
|
|
875
1102
|
};
|
|
876
1103
|
}
|
|
877
|
-
/** @deprecated Use `createRecipesExtension`. */
|
|
878
|
-
export const createPiRecipesExtension = createRecipesExtension;
|
|
879
1104
|
export default createRecipesExtension();
|
|
880
1105
|
//# sourceMappingURL=pi-extension.js.map
|