History

refactor(v2): rename PM runtime surface to runtime host

Align runtime naming with the current architecture by replacing PM-prefixed runtime services/env wiring with runtime-host terminology while keeping legacy PM env vars as fallbacks for compatibility.

Rhys Sullivan committed 8 months ago

Commit be4adee1 parent 7b46af718 files · +113 −312Browse files

Unified · Split

18 files
  1. PLAN.md +6 −6
  2. apps/cli/README.md +9 −3
  3. apps/cli/src/main.ts +5 −227
  4. apps/web/lib/control-plane/server.ts +27 −27
  5. apps/web/lib/env/server.ts +19 −6
  6. packages/control-plane-runtime/src/actor.ts +8 −5
  7. packages/control-plane-runtime/src/approvals-service.ts +4 −4
  8. packages/control-plane-runtime/src/credential-resolver.ts +1 −1
  9. packages/control-plane-runtime/src/credentials-service.ts +1 −1
  10. packages/control-plane-runtime/src/index.ts +12 −12
  11. packages/control-plane-runtime/src/mcp-handler.ts +4 −4
  12. packages/control-plane-runtime/src/organizations-service.ts +1 −1
  13. packages/control-plane-runtime/src/policies-service.ts +1 −1
  14. packages/control-plane-runtime/src/runtime-execution-port.ts +11 −11
  15. packages/control-plane-runtime/src/storage-service.ts +1 −1
  16. packages/control-plane-runtime/src/tools-service.ts +1 −1
  17. packages/control-plane-runtime/src/workspaces-service.ts +1 −1
  18. turbo.json +1 −0
PLAN.md+6−6
@@ -104,7 +104,7 @@ Important boundary: · 103 unmodified lines
104 104
105### Modes105### Modes
106 106
107- local-lite: PM daemon + in-memory hot state + file durability107- local-lite: Runtime Host daemon + in-memory hot state + file durability
108- remote: SQL-backed target (Postgres remote, SQLite local)108- remote: SQL-backed target (Postgres remote, SQLite local)
109 109
110### Runtime targets110### Runtime targets
@@ -265,7 +265,7 @@ Secrets/credentials: · 154 unmodified lines
265---265---
266 266
267## 12) Security posture267## 12) Security posture
268- PM binds to loopback by default.268- Runtime Host binds to loopback by default.
269- Runtime callbacks require internal token validation.269- Runtime callbacks require internal token validation.
270- Secrets do not pass through model args/transcripts.270- Secrets do not pass through model args/transcripts.
271- Credential refs in state; secret values in secure stores.271- Credential refs in state; secret values in secure stores.
@@ -279,7 +279,7 @@ Secrets/credentials: · 7 unmodified lines
279v2/279v2/
280 apps/280 apps/
281 cli/281 cli/
282 pm/282 runtime-host/
283 web/283 web/
284 packages/284 packages/
285 schema/285 schema/
@@ -340,7 +340,7 @@ Rules: · 54 unmodified lines
340 340
341### Phase 1: local-lite execute vertical slice341### Phase 1: local-lite execute vertical slice
342 342
343- PM execute path with persisted run lifecycle343- Runtime Host execute path with persisted run lifecycle
344- runtime callback path wired through shared invocation service344- runtime callback path wired through shared invocation service
345- openapi + in_memory providers345- openapi + in_memory providers
346 346
@@ -403,7 +403,7 @@ Implemented in `v2` so far: · 56 unmodified lines
403- local in-process JS runner with `tools.*` proxy403- local in-process JS runner with `tools.*` proxy
404- Deno subprocess runtime path with IPC tool-call proxying and tests404- Deno subprocess runtime path with IPC tool-call proxying and tests
405- runtime adapter contract + registry scaffold405- runtime adapter contract + registry scaffold
406- PM execute lifecycle scaffold via MCP execute path406- Runtime Host execute lifecycle scaffold via MCP execute path
407 407
408Still missing:408Still missing:
409 409
@@ -417,7 +417,7 @@ Still missing: · 7 unmodified lines
417 417
418## 19) Immediate next steps418## 19) Immediate next steps
419 419
4201. Land shared `ToolInvocationService` contract in v2 and wire PM execute callback path through it.4201. Land shared `ToolInvocationService` contract in v2 and wire Runtime Host execute callback path through it.
4212. Add `CredentialResolver` interfaces and local/remote implementations; integrate at invocation-time only.4212. Add `CredentialResolver` interfaces and local/remote implementations; integrate at invocation-time only.
4223. Implement control handlers for sources (`add/list/remove`) and route both host API and `tools.executor.*` through same code path.4223. Implement control handlers for sources (`add/list/remove`) and route both host API and `tools.executor.*` through same code path.
4234. Implement cloudflare-worker-loader runtime dispatch adapter in v2 and wire callback endpoints.4234. Implement cloudflare-worker-loader runtime dispatch adapter in v2 and wire callback endpoints.
apps/cli/README.md+9−3
@@ -26,13 +26,19 @@ Supported commands: · 25 unmodified lines
26- `executor workspace use <workspace-id>`26- `executor workspace use <workspace-id>`
27- `executor run execute --code ...`27- `executor run execute --code ...`
28- `executor run execute --file ...`28- `executor run execute --file ...`
29- `executor run bootstrap openapi --spec-url ... --source-base-url ...`29
30- `executor run bootstrap github`30Control-plane management from CLI should happen through `run execute` and discovered
31source tool paths (for example, add Executor's own OpenAPI source, then call its
32tool paths to manage other sources).
31 33
32Run locally:34Run locally:
33 35
34- `bun run --cwd apps/cli start -- target show`36- `bun run --cwd apps/cli start -- target show`
35- `bun run --cwd apps/cli start -- run execute --target local --code "return 1"`37- `bun run --cwd apps/cli start -- run execute --target local --code "return 1"`
36- `bun run --cwd apps/cli start -- run bootstrap github --target local`
37- `bun run --cwd apps/cli start -- --help`38- `bun run --cwd apps/cli start -- --help`
38- `bun run --cwd apps/cli start -- server start --port 8788`39- `bun run --cwd apps/cli start -- server start --port 8788`
40
41Seed Executor's own OpenAPI source (example):
42
43- `bun run --cwd apps/cli start -- run execute --target local --workspace ws_local --code "const workspaceId='ws_local'; const res=await fetch('http://127.0.0.1:8788/v1/workspaces/'+workspaceId+'/sources',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({id:'src_executor_openapi',name:'executor:openapi',kind:'openapi',endpoint:'http://127.0.0.1:8788/v1/openapi.json',enabled:true,configJson:JSON.stringify({baseUrl:'http://127.0.0.1:8788'})})}); return await res.json();"`
44- Then use `tools.discover(...)` in `run execute` to locate and call source tool paths.
apps/cli/src/main.ts+5−227
@@ -36,20 +36,6 @@ type WorkspaceRecord = { · 35 unmodified lines
36 id: string;36 id: string;
37};37};
38 38
39type SourceRecord = {
40 id: string;
41 name: string;
42 endpoint: string;
43 configJson: string;
44};
45
46type SourceToolSummaryRecord = {
47 toolId: string;
48 method: string;
49 path: string;
50 name: string;
51};
52
53type DeviceAuthorizationResponse = {39type DeviceAuthorizationResponse = {
54 device_code: string;40 device_code: string;
55 user_code: string;41 user_code: string;
@@ -78,10 +64,6 @@ type CommonTargetOptions = { · 22 unmodified lines
78 64
79const DEFAULT_LOCAL_BASE_URL = "http://127.0.0.1:8788";65const DEFAULT_LOCAL_BASE_URL = "http://127.0.0.1:8788";
80const DEFAULT_WORKOS_AUTH_BASE_URL = "https://api.workos.com";66const DEFAULT_WORKOS_AUTH_BASE_URL = "https://api.workos.com";
81const DEFAULT_GITHUB_OPENAPI_SPEC_URL =
82 "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json";
83const DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
84const DEFAULT_GITHUB_OPENAPI_SOURCE_ID = "src_github_openapi";
85const CONFIG_PATH = join(homedir(), ".config", "executor", "cli.json");67const CONFIG_PATH = join(homedir(), ".config", "executor", "cli.json");
86 68
87const toErrorMessage = (cause: unknown): string =>69const toErrorMessage = (cause: unknown): string =>
@@ -518,6 +500,8 @@ class ExecutorServerClient { · 430 unmodified lines
518 const childEnv = {500 const childEnv = {
519 ...cleanEnv(),501 ...cleanEnv(),
520 PORT: localPort,502 PORT: localPort,
503 EXECUTOR_RUNTIME_KIND:
504 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc",
521 PM_RUNTIME_KIND:505 PM_RUNTIME_KIND:
522 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc",506 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc",
523 };507 };
@@ -597,87 +581,6 @@ const ensureWorkspaceId = async ( · 73 unmodified lines
597 return workspaceId;581 return workspaceId;
598};582};
599 583
600const deriveSourceName = (kind: string, endpoint: string): string => {
601 try {
602 const url = new URL(endpoint);
603 const host = url.hostname.replace(/^api\./, "");
604 return `${kind}:${host}`;
605 } catch {
606 return `${kind}:source`;
607 }
608};
609
610const bootstrapOpenApiSource = async (input: {
611 client: ExecutorServerClient;
612 config: ExecutorCliConfig;
613 workspaceOverride?: string;
614 specUrl: string;
615 baseUrl: string;
616 name?: string;
617 sourceId?: string;
618}): Promise<{
619 workspaceId: string;
620 source: SourceRecord;
621 tools: Array<SourceToolSummaryRecord>;
622 sampleToolPath: string | null;
623}> => {
624 const workspaceId = await ensureWorkspaceId(
625 input.client,
626 input.config,
627 input.workspaceOverride,
628 );
629 const normalizedSpecUrl = input.specUrl.trim();
630 const normalizedBaseUrl = input.baseUrl.trim();
631
632 if (normalizedSpecUrl.length === 0) {
633 throw new Error("OpenAPI bootstrap requires --spec-url.");
634 }
635
636 if (normalizedBaseUrl.length === 0) {
637 throw new Error("OpenAPI bootstrap requires --source-base-url.");
638 }
639
640 const source = await input.client.runControlPlane((api) =>
641 api.sources.upsert({
642 path: { workspaceId },
643 payload: {
644 ...(input.sourceId && input.sourceId.trim().length > 0
645 ? { id: input.sourceId.trim() }
646 : {}),
647 name:
648 input.name && input.name.trim().length > 0
649 ? input.name.trim()
650 : deriveSourceName("openapi", normalizedBaseUrl),
651 kind: "openapi",
652 endpoint: normalizedSpecUrl,
653 status: "connected",
654 enabled: true,
655 configJson: JSON.stringify({ baseUrl: normalizedBaseUrl }),
656 },
657 }),
658 ) as SourceRecord;
659
660 const tools = await input.client.runControlPlane((api) =>
661 api.tools.listSourceTools({
662 path: {
663 workspaceId,
664 sourceId: source.id,
665 },
666 }),
667 ) as Array<SourceToolSummaryRecord>;
668
669 const sampleToolPath = tools[0]?.toolId
670 ? `source.${source.id}.${tools[0].toolId}`
671 : null;
672
673 return {
674 workspaceId,
675 source,
676 tools,
677 sampleToolPath,
678 };
679};
680
681const postForm = async (584const postForm = async (
682 url: string,585 url: string,
683 params: Record<string, string>,586 params: Record<string, string>,
@@ -859,8 +762,9 @@ const commonTargetOptions = () => ({ · 175 unmodified lines
859});762});
860 763
861const startEmbeddedLocalServer = async (port: number): Promise<void> => {764const startEmbeddedLocalServer = async (port: number): Promise<void> => {
862 process.env.PM_RUNTIME_KIND =765 process.env.EXECUTOR_RUNTIME_KIND =
863 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc";766 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc";
767 process.env.PM_RUNTIME_KIND = process.env.EXECUTOR_RUNTIME_KIND;
864 768
865 const {769 const {
866 createLocalPrincipal,770 createLocalPrincipal,
@@ -1254,134 +1158,8 @@ const runExecuteCommand = Command.make( · 387 unmodified lines
1254 Command.withDescription("Execute TypeScript code through Executor runtime"),1158 Command.withDescription("Execute TypeScript code through Executor runtime"),
1255);1159);
1256 1160
1257const runBootstrapOpenApiCommand = Command.make(
1258 "openapi",
1259 {
1260 ...commonTargetOptions(),
1261 specUrl: Options.text("spec-url"),
1262 sourceBaseUrl: Options.text("source-base-url"),
1263 name: Options.text("name").pipe(Options.optional),
1264 sourceId: Options.text("source-id").pipe(Options.optional),
1265 },
1266 (input) =>
1267 Effect.tryPromise({
1268 try: async () => {
1269 const common: CommonTargetOptions = {
1270 target: input.target,
1271 workspace: input.workspace,
1272 baseUrl: input.baseUrl,
1273 json: input.json,
1274 };
1275
1276 await withClient(common, async ({ client, config, workspaceOverride, asJson }) => {
1277 const setup = await bootstrapOpenApiSource({
1278 client,
1279 config,
1280 workspaceOverride,
1281 specUrl: input.specUrl,
1282 baseUrl: input.sourceBaseUrl,
1283 name: optionToUndefined(input.name),
1284 sourceId: optionToUndefined(input.sourceId),
1285 });
1286
1287 printOutput(
1288 {
1289 ok: true,
1290 workspaceId: setup.workspaceId,
1291 source: {
1292 id: setup.source.id,
1293 name: setup.source.name,
1294 endpoint: setup.source.endpoint,
1295 configJson: setup.source.configJson,
1296 },
1297 toolCount: setup.tools.length,
1298 sampleToolPath: setup.sampleToolPath,
1299 },
1300 asJson,
1301 );
1302 });
1303 },
1304 catch: toErrorMessage,
1305 }),
1306).pipe(
1307 Command.withDescription("Bootstrap an OpenAPI source with runtime base URL"),
1308);
1309
1310const runBootstrapGithubCommand = Command.make(
1311 "github",
1312 {
1313 ...commonTargetOptions(),
1314 name: Options.text("name").pipe(Options.optional),
1315 sourceId: Options.text("source-id").pipe(Options.optional),
1316 specUrl: Options.text("spec-url").pipe(Options.withDefault(DEFAULT_GITHUB_OPENAPI_SPEC_URL)),
1317 sourceBaseUrl: Options.text("source-base-url").pipe(Options.withDefault(DEFAULT_GITHUB_API_BASE_URL)),
1318 },
1319 (input) =>
1320 Effect.tryPromise({
1321 try: async () => {
1322 const common: CommonTargetOptions = {
1323 target: input.target,
1324 workspace: input.workspace,
1325 baseUrl: input.baseUrl,
1326 json: input.json,
1327 };
1328
1329 await withClient(common, async ({ client, config, workspaceOverride, asJson }) => {
1330 const setup = await bootstrapOpenApiSource({
1331 client,
1332 config,
1333 workspaceOverride,
1334 specUrl: input.specUrl,
1335 baseUrl: input.sourceBaseUrl,
1336 name: optionToUndefined(input.name) ?? "github:openapi",
1337 sourceId: optionToUndefined(input.sourceId) ?? DEFAULT_GITHUB_OPENAPI_SOURCE_ID,
1338 });
1339
1340 const suggestedTool =
1341 setup.tools.find((tool) =>
1342 tool.toolId.includes("issues-and-pull-requests"),
1343 )
1344 ?? setup.tools[0]
1345 ?? null;
1346
1347 printOutput(
1348 {
1349 ok: true,
1350 workspaceId: setup.workspaceId,
1351 source: {
1352 id: setup.source.id,
1353 name: setup.source.name,
1354 endpoint: setup.source.endpoint,
1355 configJson: setup.source.configJson,
1356 },
1357 toolCount: setup.tools.length,
1358 suggestedToolPath: suggestedTool
1359 ? `source.${setup.source.id}.${suggestedTool.toolId}`
1360 : null,
1361 executeHint: suggestedTool
1362 ? `executor run execute --code \"return await tools['source.${setup.source.id}.${suggestedTool.toolId}']({ q: 'repo:owner/repo is:issue state:open', per_page: 5 });\"`
1363 : null,
1364 },
1365 asJson,
1366 );
1367 });
1368 },
1369 catch: toErrorMessage,
1370 }),
1371).pipe(
1372 Command.withDescription("Bootstrap GitHub OpenAPI source for public issue queries"),
1373);
1374
1375const runBootstrapCommand = Command.make("bootstrap").pipe(
1376 Command.withSubcommands([
1377 runBootstrapOpenApiCommand,
1378 runBootstrapGithubCommand,
1379 ] as any),
1380 Command.withDescription("Bootstrap source setup shortcuts for execution workflows"),
1381);
1382
1383const runCommand = Command.make("run").pipe(1161const runCommand = Command.make("run").pipe(
1384 Command.withSubcommands([runExecuteCommand, runBootstrapCommand] as any),1162 Command.withSubcommands([runExecuteCommand] as any),
1385 Command.withDescription("Code execution commands"),1163 Command.withDescription("Code execution commands"),
1386);1164);
1387 1165
apps/web/lib/control-plane/server.ts+27−27
@@ -30,19 +30,19 @@ import { · 29 unmodified lines
30 type ToolRegistryDiscoverOutput,30 type ToolRegistryDiscoverOutput,
31} from "@executor-v2/engine";31} from "@executor-v2/engine";
32import {32import {
33 PmActorLive,33 RuntimeHostActorLive,
34 createKeychainSecretMaterialStore,34 createKeychainSecretMaterialStore,
35 createPmApprovalsService,35 createRuntimeHostApprovalsService,
36 createPmCredentialsService,36 createRuntimeHostCredentialsService,
37 createPmExecuteRuntimeRun,37 createRuntimeHostExecuteRuntimeRun,
38 createPmMcpHandler,38 createRuntimeHostMcpHandler,
39 createPmOrganizationsService,39 createRuntimeHostOrganizationsService,
40 createPmPersistentToolApprovalPolicy,40 createRuntimeHostPersistentToolApprovalPolicy,
41 createPmPoliciesService,41 createRuntimeHostPoliciesService,
42 createPmResolveToolCredentials,42 createRuntimeHostResolveToolCredentials,
43 createPmStorageService,43 createRuntimeHostStorageService,
44 createPmToolsService,44 createRuntimeHostToolsService,
45 createPmWorkspacesService,45 createRuntimeHostWorkspacesService,
46 createSqlSecretMaterialStore,46 createSqlSecretMaterialStore,
47 parseSecretMaterialBackendKind,47 parseSecretMaterialBackendKind,
48} from "@executor-v2/control-plane-runtime";48} from "@executor-v2/control-plane-runtime";
@@ -585,25 +585,25 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 536 unmodified lines
585 ];585 ];
586 const runtimeAdapters = makeRuntimeAdapterRegistry(runtimeAdapterList);586 const runtimeAdapters = makeRuntimeAdapterRegistry(runtimeAdapterList);
587 const defaultRuntimeKind =587 const defaultRuntimeKind =
588 webServerEnvironment.pmRuntimeKind588 webServerEnvironment.executorRuntimeKind
589 ?? runtimeAdapterList[0]?.kind589 ?? runtimeAdapterList[0]?.kind
590 ?? "local-inproc";590 ?? "local-inproc";
591 const requireToolApprovals = webServerEnvironment.pmRequireToolApprovals;591 const requireToolApprovals = webServerEnvironment.executorRuntimeRequireToolApprovals;
592 const defaultToolExposureMode =592 const defaultToolExposureMode =
593 parseExecuteToolExposureMode(webServerEnvironment.pmToolExposureMode)593 parseExecuteToolExposureMode(webServerEnvironment.executorRuntimeToolExposureMode)
594 ?? defaultExecuteToolExposureMode;594 ?? defaultExecuteToolExposureMode;
595 const toolProviderRegistry = makeToolProviderRegistry([595 const toolProviderRegistry = makeToolProviderRegistry([
596 makeOpenApiToolProvider(),596 makeOpenApiToolProvider(),
597 makeMcpToolProvider(),597 makeMcpToolProvider(),
598 makeGraphqlToolProvider(),598 makeGraphqlToolProvider(),
599 ]);599 ]);
600 const persistentApprovalPolicy = createPmPersistentToolApprovalPolicy(600 const persistentApprovalPolicy = createRuntimeHostPersistentToolApprovalPolicy(
601 persistence.rows,601 persistence.rows,
602 {602 {
603 requireApprovals: requireToolApprovals,603 requireApprovals: requireToolApprovals,
604 },604 },
605 );605 );
606 const resolveCredentials = createPmResolveToolCredentials(606 const resolveCredentials = createRuntimeHostResolveToolCredentials(
607 persistence.rows,607 persistence.rows,
608 secretMaterialStore,608 secretMaterialStore,
609 );609 );
@@ -722,20 +722,20 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 112 unmodified lines
722 722
723 const controlPlaneService = makeControlPlaneService({723 const controlPlaneService = makeControlPlaneService({
724 sources: sourcesService,724 sources: sourcesService,
725 credentials: createPmCredentialsService(persistence.rows, secretMaterialStore),725 credentials: createRuntimeHostCredentialsService(persistence.rows, secretMaterialStore),
726 policies: createPmPoliciesService(persistence.rows),726 policies: createRuntimeHostPoliciesService(persistence.rows),
727 organizations: createPmOrganizationsService(persistence.rows),727 organizations: createRuntimeHostOrganizationsService(persistence.rows),
728 workspaces: createPmWorkspacesService(persistence.rows),728 workspaces: createRuntimeHostWorkspacesService(persistence.rows),
729 tools: createPmToolsService(sourceStore, toolArtifactStore),729 tools: createRuntimeHostToolsService(sourceStore, toolArtifactStore),
730 storage: createPmStorageService(persistence.rows, {730 storage: createRuntimeHostStorageService(persistence.rows, {
731 stateRootDir,731 stateRootDir,
732 }),732 }),
733 approvals: createPmApprovalsService(persistence.rows),733 approvals: createRuntimeHostApprovalsService(persistence.rows),
734 });734 });
735 735
736 const controlPlaneWebHandler = makeControlPlaneWebHandler(736 const controlPlaneWebHandler = makeControlPlaneWebHandler(
737 Layer.succeed(ControlPlaneService, controlPlaneService),737 Layer.succeed(ControlPlaneService, controlPlaneService),
738 PmActorLive(persistence.rows),738 RuntimeHostActorLive(persistence.rows),
739 );739 );
740 740
741 const rememberRunWorkspace = (runId: string, workspaceId: string): void => {741 const rememberRunWorkspace = (runId: string, workspaceId: string): void => {
@@ -772,7 +772,7 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 30 unmodified lines
772 toolProviderRegistry,772 toolProviderRegistry,
773 approvalPolicy: persistentApprovalPolicy,773 approvalPolicy: persistentApprovalPolicy,
774 });774 });
775 const executeRuntimeRun = createPmExecuteRuntimeRun({775 const executeRuntimeRun = createRuntimeHostExecuteRuntimeRun({
776 defaultRuntimeKind,776 defaultRuntimeKind,
777 runtimeAdapters,777 runtimeAdapters,
778 toolRegistry,778 toolRegistry,
@@ -784,7 +784,7 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 5 unmodified lines
784 return runId;784 return runId;
785 },785 },
786 });786 });
787 const next = createPmMcpHandler(runExecutor.executeRun, {787 const next = createRuntimeHostMcpHandler(runExecutor.executeRun, {
788 toolRegistry,788 toolRegistry,
789 defaultToolExposureMode,789 defaultToolExposureMode,
790 });790 });
apps/web/lib/env/server.ts+19−6
@@ -8,9 +8,18 @@ const webServerEnvConfig = configSchema("WebServerEnvironment", { · 7 unmodified lines
8 env: "CONTROL_PLANE_POSTGRES_CONNECTION_TARGET",8 env: "CONTROL_PLANE_POSTGRES_CONNECTION_TARGET",
9 optional: true,9 optional: true,
10 }),10 }),
11 pmRuntimeKind: server({ env: "PM_RUNTIME_KIND", optional: true }),11 executorRuntimeKind: server({ env: "EXECUTOR_RUNTIME_KIND", optional: true }),
12 pmRequireToolApprovals: server({ env: "PM_REQUIRE_TOOL_APPROVALS", optional: true }),12 legacyPmRuntimeKind: server({ env: "PM_RUNTIME_KIND", optional: true }),
13 pmToolExposureMode: server({ env: "PM_TOOL_EXPOSURE_MODE", optional: true }),13 executorRuntimeRequireToolApprovals: server({
14 env: "EXECUTOR_RUNTIME_REQUIRE_TOOL_APPROVALS",
15 optional: true,
16 }),
17 legacyPmRequireToolApprovals: server({ env: "PM_REQUIRE_TOOL_APPROVALS", optional: true }),
18 executorRuntimeToolExposureMode: server({
19 env: "EXECUTOR_RUNTIME_TOOL_EXPOSURE_MODE",
20 optional: true,
21 }),
22 legacyPmToolExposureMode: server({ env: "PM_TOOL_EXPOSURE_MODE", optional: true }),
14 cloudflareSandboxCallbackSecret: server({23 cloudflareSandboxCallbackSecret: server({
15 env: "CLOUDFLARE_SANDBOX_CALLBACK_SECRET",24 env: "CLOUDFLARE_SANDBOX_CALLBACK_SECRET",
16 optional: true,25 optional: true,
@@ -36,14 +45,18 @@ const webServerEnvConfig = configSchema("WebServerEnvironment", { · 19 unmodified lines
36});45});
37 46
38const env = webServerEnvConfig.server;47const env = webServerEnvConfig.server;
48const executorRuntimeRequireToolApprovalsRaw =
49 trim(env.executorRuntimeRequireToolApprovals)
50 ?? trim(env.legacyPmRequireToolApprovals);
39 51
40export const webServerEnvironment = {52export const webServerEnvironment = {
41 nodeEnv: trim(env.nodeEnv) ?? "development",53 nodeEnv: trim(env.nodeEnv) ?? "development",
42 databaseUrl: trim(env.databaseUrl),54 databaseUrl: trim(env.databaseUrl),
43 controlPlanePostgresConnectionTarget: trim(env.controlPlanePostgresConnectionTarget)?.toLowerCase(),55 controlPlanePostgresConnectionTarget: trim(env.controlPlanePostgresConnectionTarget)?.toLowerCase(),
44 pmRuntimeKind: trim(env.pmRuntimeKind),56 executorRuntimeKind: trim(env.executorRuntimeKind) ?? trim(env.legacyPmRuntimeKind),
45 pmRequireToolApprovals: isTruthy(env.pmRequireToolApprovals),57 executorRuntimeRequireToolApprovals: isTruthy(executorRuntimeRequireToolApprovalsRaw),
46 pmToolExposureMode: trim(env.pmToolExposureMode),58 executorRuntimeToolExposureMode:
59 trim(env.executorRuntimeToolExposureMode) ?? trim(env.legacyPmToolExposureMode),
47 cloudflareSandboxCallbackSecret: trim(env.cloudflareSandboxCallbackSecret),60 cloudflareSandboxCallbackSecret: trim(env.cloudflareSandboxCallbackSecret),
48 executorPublicOrigin: trim(env.executorPublicOrigin),61 executorPublicOrigin: trim(env.executorPublicOrigin),
49 vercelProjectProductionUrl: trim(env.vercelProjectProductionUrl),62 vercelProjectProductionUrl: trim(env.vercelProjectProductionUrl),
packages/control-plane-runtime/src/actor.ts+8−5
@@ -84,14 +84,17 @@ const resolveActorFromSnapshot = ( · 83 unmodified lines
84 });84 });
85 });85 });
86 86
87export const PmActorLive = (rows: ActorRows) =>87export const RuntimeHostActorLive = (rows: ActorRows) =>
88 {88 {
89 const localAdminFallbackValue =
90 process.env.EXECUTOR_RUNTIME_ALLOW_LOCAL_ADMIN?.trim().toLowerCase()
91 ?? process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase()
92 ?? "";
93
89 const localAdminFallbackEnabled =94 const localAdminFallbackEnabled =
90 (process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase() ?? "") === ""95 localAdminFallbackValue === ""
91 ? process.env.NODE_ENV !== "production"96 ? process.env.NODE_ENV !== "production"
92 : ["1", "true", "yes"].includes(97 : ["1", "true", "yes"].includes(localAdminFallbackValue);
93 process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase() ?? "",
94 );
95 98
96 return ControlPlaneActorResolverLive({99 return ControlPlaneActorResolverLive({
97 resolveActor: (input) => resolveActorFromSnapshot(rows, input.headers, localAdminFallbackEnabled),100 resolveActor: (input) => resolveActorFromSnapshot(rows, input.headers, localAdminFallbackEnabled),
packages/control-plane-runtime/src/approvals-service.ts+4−4
@@ -47,14 +47,14 @@ const toPersistentApprovalRecord = (approval: Approval): PersistentToolApprovalR · 46 unmodified lines
47 reason: approval.reason,47 reason: approval.reason,
48});48});
49 49
50export type PmPersistentToolApprovalPolicyOptions = {50export type RuntimeHostPersistentToolApprovalPolicyOptions = {
51 requireApprovals?: boolean;51 requireApprovals?: boolean;
52 retryAfterMs?: number;52 retryAfterMs?: number;
53};53};
54 54
55export const createPmPersistentToolApprovalPolicy = (55export const createRuntimeHostPersistentToolApprovalPolicy = (
56 rows: ApprovalRows,56 rows: ApprovalRows,
57 options: PmPersistentToolApprovalPolicyOptions = {},57 options: RuntimeHostPersistentToolApprovalPolicyOptions = {},
58): ToolApprovalPolicy => {58): ToolApprovalPolicy => {
59 const store: PersistentToolApprovalStore = {59 const store: PersistentToolApprovalStore = {
60 findByRunAndCall: (input) =>60 findByRunAndCall: (input) =>
@@ -106,7 +106,7 @@ export const createPmPersistentToolApprovalPolicy = ( · 45 unmodified lines
106 });106 });
107};107};
108 108
109export const createPmApprovalsService = (109export const createRuntimeHostApprovalsService = (
110 rows: ApprovalRows,110 rows: ApprovalRows,
111): ControlPlaneApprovalsServiceShape =>111): ControlPlaneApprovalsServiceShape =>
112 makeControlPlaneApprovalsService({112 makeControlPlaneApprovalsService({
packages/control-plane-runtime/src/credential-resolver.ts+1−1
@@ -163,7 +163,7 @@ const buildSecretHeaders = ( · 162 unmodified lines
163 return {};163 return {};
164};164};
165 165
166export const createPmResolveToolCredentials = (166export const createRuntimeHostResolveToolCredentials = (
167 rows: CredentialResolverRows,167 rows: CredentialResolverRows,
168 secretMaterialStore: SecretMaterialStore,168 secretMaterialStore: SecretMaterialStore,
169): ResolveToolCredentials =>169): ResolveToolCredentials =>
packages/control-plane-runtime/src/credentials-service.ts+1−1
@@ -73,7 +73,7 @@ const uniqueHandles = (handles: ReadonlyArray<string | null | undefined>): Array · 72 unmodified lines
73 return next;73 return next;
74};74};
75 75
76export const createPmCredentialsService = (76export const createRuntimeHostCredentialsService = (
77 rows: CredentialRows,77 rows: CredentialRows,
78 secretMaterialStore: SecretMaterialStore,78 secretMaterialStore: SecretMaterialStore,
79): ControlPlaneCredentialsServiceShape =>79): ControlPlaneCredentialsServiceShape =>
packages/control-plane-runtime/src/index.ts+12−12
@@ -1,14 +1,14 @@
1export { PmActorLive } from "./actor";1export { RuntimeHostActorLive } from "./actor";
2export {2export {
3 createPmApprovalsService,3 createRuntimeHostApprovalsService,
4 createPmPersistentToolApprovalPolicy,4 createRuntimeHostPersistentToolApprovalPolicy,
5} from "./approvals-service";5} from "./approvals-service";
6export { createPmResolveToolCredentials } from "./credential-resolver";6export { createRuntimeHostResolveToolCredentials } from "./credential-resolver";
7export { createPmCredentialsService } from "./credentials-service";7export { createRuntimeHostCredentialsService } from "./credentials-service";
8export { createPmMcpHandler } from "./mcp-handler";8export { createRuntimeHostMcpHandler } from "./mcp-handler";
9export { createPmOrganizationsService } from "./organizations-service";9export { createRuntimeHostOrganizationsService } from "./organizations-service";
10export { createPmPoliciesService } from "./policies-service";10export { createRuntimeHostPoliciesService } from "./policies-service";
11export { createPmExecuteRuntimeRun } from "./runtime-execution-port";11export { createRuntimeHostExecuteRuntimeRun } from "./runtime-execution-port";
12export {12export {
13 createKeychainSecretMaterialStore,13 createKeychainSecretMaterialStore,
14 createSqlSecretMaterialStore,14 createSqlSecretMaterialStore,
@@ -19,6 +19,6 @@ export { · 4 unmodified lines
19 type SecretMaterialScope,19 type SecretMaterialScope,
20 type SecretMaterialStore,20 type SecretMaterialStore,
21} from "./secret-material-store";21} from "./secret-material-store";
22export { createPmStorageService } from "./storage-service";22export { createRuntimeHostStorageService } from "./storage-service";
23export { createPmToolsService } from "./tools-service";23export { createRuntimeHostToolsService } from "./tools-service";
24export { createPmWorkspacesService } from "./workspaces-service";24export { createRuntimeHostWorkspacesService } from "./workspaces-service";
packages/control-plane-runtime/src/mcp-handler.ts+4−4
@@ -14,7 +14,7 @@ import { · 13 unmodified lines
14import { handleMcpHttpRequest } from "@executor-v2/mcp-gateway";14import { handleMcpHttpRequest } from "@executor-v2/mcp-gateway";
15import * as Effect from "effect/Effect";15import * as Effect from "effect/Effect";
16 16
17export type PmMcpHandlerOptions = {17export type RuntimeHostMcpHandlerOptions = {
18 toolRegistry: ToolRegistry;18 toolRegistry: ToolRegistry;
19 defaultToolExposureMode?: ExecuteToolExposureMode;19 defaultToolExposureMode?: ExecuteToolExposureMode;
20};20};
@@ -48,9 +48,9 @@ const resolveExecuteToolDescription = async ( · 27 unmodified lines
48 }48 }
49};49};
50 50
51export const createPmMcpHandler = (51export const createRuntimeHostMcpHandler = (
52 executeRun: (input: ExecuteRunInput) => Effect.Effect<ExecuteRunResult>,52 executeRun: (input: ExecuteRunInput) => Effect.Effect<ExecuteRunResult>,
53 options: PmMcpHandlerOptions,53 options: RuntimeHostMcpHandlerOptions,
54): ((request: Request) => Promise<Response>) => {54): ((request: Request) => Promise<Response>) => {
55 const runClient = createExecutorRunClient((input) =>55 const runClient = createExecutorRunClient((input) =>
56 Effect.runPromise(executeRun(input)),56 Effect.runPromise(executeRun(input)),
@@ -67,7 +67,7 @@ export const createPmMcpHandler = ( · 10 unmodified lines
67 );67 );
68 68
69 return handleMcpHttpRequest(request, {69 return handleMcpHttpRequest(request, {
70 serverName: "executor-v2-pm",70 serverName: "executor-v2-runtime-host",
71 serverVersion: "0.0.0",71 serverVersion: "0.0.0",
72 runClient,72 runClient,
73 executeToolDescription,73 executeToolDescription,
packages/control-plane-runtime/src/organizations-service.ts+1−1
@@ -33,7 +33,7 @@ const sortOrganizations = ( · 32 unmodified lines
33 return leftName.localeCompare(rightName);33 return leftName.localeCompare(rightName);
34 });34 });
35 35
36export const createPmOrganizationsService = (36export const createRuntimeHostOrganizationsService = (
37 rows: OrganizationRows,37 rows: OrganizationRows,
38): ControlPlaneOrganizationsServiceShape =>38): ControlPlaneOrganizationsServiceShape =>
39 makeControlPlaneOrganizationsService({39 makeControlPlaneOrganizationsService({
packages/control-plane-runtime/src/policies-service.ts+1−1
@@ -24,7 +24,7 @@ const sortPolicies = (policies: ReadonlyArray<Policy>): Array<Policy> => · 23 unmodified lines
24 return leftPattern.localeCompare(rightPattern);24 return leftPattern.localeCompare(rightPattern);
25 });25 });
26 26
27export const createPmPoliciesService = (27export const createRuntimeHostPoliciesService = (
28 rows: PolicyRows,28 rows: PolicyRows,
29): ControlPlanePoliciesServiceShape =>29): ControlPlanePoliciesServiceShape =>
30 makeControlPlanePoliciesService({30 makeControlPlanePoliciesService({
packages/control-plane-runtime/src/runtime-execution-port.ts+11−11
@@ -9,14 +9,14 @@ import { · 8 unmodified lines
9} from "@executor-v2/engine";9} from "@executor-v2/engine";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11 11
12export type PmRuntimeExecutionPortOptions = {12export type RuntimeHostExecutionPortOptions = {
13 defaultRuntimeKind: string;13 defaultRuntimeKind: string;
14 runtimeAdapters: RuntimeAdapterRegistry;14 runtimeAdapters: RuntimeAdapterRegistry;
15 toolRegistry: ToolRegistry;15 toolRegistry: ToolRegistry;
16};16};
17 17
18export const createPmExecuteRuntimeRun = (18export const createRuntimeHostExecuteRuntimeRun = (
19 options: PmRuntimeExecutionPortOptions,19 options: RuntimeHostExecutionPortOptions,
20): ExecuteRuntimeRun => {20): ExecuteRuntimeRun => {
21 const runtimeToolCallService = createRuntimeToolCallService(options.toolRegistry);21 const runtimeToolCallService = createRuntimeToolCallService(options.toolRegistry);
22 22
@@ -35,14 +35,14 @@ export const createPmExecuteRuntimeRun = ( · 12 unmodified lines
35 ),35 ),
36 );36 );
37 37
38 const isAvailable = yield* runtimeAdapter.isAvailable();38 const isAvailable = yield* runtimeAdapter.isAvailable();
39 if (!isAvailable) {39 if (!isAvailable) {
40 return yield* new RuntimeExecutionPortError({40 return yield* new RuntimeExecutionPortError({
41 operation: "runtime_available",41 operation: "runtime_available",
42 message: `Runtime '${options.defaultRuntimeKind}' is not available in this pm process.`,42 message: `Runtime '${options.defaultRuntimeKind}' is not available in this runtime host process.`,
43 details: null,43 details: null,
44 });44 });
45 }45 }
46 46
47 return yield* runtimeAdapter47 return yield* runtimeAdapter
48 .execute({48 .execute({
packages/control-plane-runtime/src/storage-service.ts+1−1
@@ -136,7 +136,7 @@ const loadStorageScope = ( · 135 unmodified lines
136 }),136 }),
137 );137 );
138 138
139export const createPmStorageService = (139export const createRuntimeHostStorageService = (
140 rows: StorageRows,140 rows: StorageRows,
141 options: {141 options: {
142 stateRootDir: string;142 stateRootDir: string;
packages/control-plane-runtime/src/tools-service.ts+1−1
@@ -141,7 +141,7 @@ const listSourceTools = ( · 140 unmodified lines
141 return yield* parseArtifactManifest(source, artifact);141 return yield* parseArtifactManifest(source, artifact);
142 });142 });
143 143
144export const createPmToolsService = (144export const createRuntimeHostToolsService = (
145 sourceStore: SourceStore,145 sourceStore: SourceStore,
146 toolArtifactStore: ToolArtifactStore,146 toolArtifactStore: ToolArtifactStore,
147): ControlPlaneToolsServiceShape =>147): ControlPlaneToolsServiceShape =>
packages/control-plane-runtime/src/workspaces-service.ts+1−1
@@ -25,7 +25,7 @@ const sortWorkspaces = (workspaces: ReadonlyArray<Workspace>): Array<Workspace> · 24 unmodified lines
25 return leftName.localeCompare(rightName);25 return leftName.localeCompare(rightName);
26 });26 });
27 27
28export const createPmWorkspacesService = (28export const createRuntimeHostWorkspacesService = (
29 rows: WorkspaceRows,29 rows: WorkspaceRows,
30): ControlPlaneWorkspacesServiceShape =>30): ControlPlaneWorkspacesServiceShape =>
31 makeControlPlaneWorkspacesService({31 makeControlPlaneWorkspacesService({
turbo.json+1−0
@@ -19,6 +19,7 @@ · 18 unmodified lines
19 "CONTROL_PLANE_POSTGRES_MAX_CONNECTIONS",19 "CONTROL_PLANE_POSTGRES_MAX_CONNECTIONS",
20 "DATABASE_URL",20 "DATABASE_URL",
21 "MCP_AUTHORIZATION_SERVER",21 "MCP_AUTHORIZATION_SERVER",
22 "EXECUTOR_RUNTIME_KIND",
22 "PM_RUNTIME_KIND",23 "PM_RUNTIME_KIND",
23 "VITE_CONVEX_URL",24 "VITE_CONVEX_URL",
24 "WORKOS_API_KEY",25 "WORKOS_API_KEY",