Merge branch 'feat/plugin-acquire-lease-agent-id' into dev

Thread agentId into PluginEnvironmentAcquireLeaseParams + host call sites
so plugin-backed sandbox providers (e.g. paperclip-plugin-k8s) can scope
lease state per-agent without needing an SDK callback or DB lookup.
This commit is contained in:
2026-05-12 07:34:00 -04:00
5 changed files with 28 additions and 0 deletions
+7
View File
@@ -379,6 +379,13 @@ export interface PluginEnvironmentLease {
export interface PluginEnvironmentAcquireLeaseParams extends PluginEnvironmentDriverBaseParams { export interface PluginEnvironmentAcquireLeaseParams extends PluginEnvironmentDriverBaseParams {
runId: string; runId: string;
/**
* UUID of the agent the run is being acquired for. Omitted only for ad-hoc
* invocations (e.g. operator-initiated environment test probes) where no
* agent context exists. Plugins should treat undefined as "no per-agent
* partitioning available" and fall back to environment-level behavior.
*/
agentId?: string;
workspaceMode?: string; workspaceMode?: string;
requestedCwd?: string; requestedCwd?: string;
} }
@@ -209,6 +209,7 @@ describeEmbeddedPostgres("heartbeat plugin environments", () => {
issueId: null, issueId: null,
config: { template: "base" }, config: { template: "base" },
runId: run!.id, runId: run!.id,
agentId,
workspaceMode: "shared_workspace", workspaceMode: "shared_workspace",
}); });
await vi.waitFor(() => { await vi.waitFor(() => {
@@ -426,6 +427,7 @@ describeEmbeddedPostgres("heartbeat plugin environments", () => {
issueId, issueId,
config: { template: "new" }, config: { template: "new" },
runId: run!.id, runId: run!.id,
agentId,
workspaceMode: "shared_workspace", workspaceMode: "shared_workspace",
}); });
}, 15_000); }, 15_000);
+1
View File
@@ -319,6 +319,7 @@ export function agentRoutes(
companyId: input.companyId, companyId: input.companyId,
environment, environment,
issueId: null, issueId: null,
agentId: null,
heartbeatRunId: null, heartbeatRunId: null,
persistedExecutionWorkspace: null, persistedExecutionWorkspace: null,
}); });
@@ -206,6 +206,7 @@ export function environmentRunOrchestrator(
companyId: string; companyId: string;
environment: Environment; environment: Environment;
issueId: string | null; issueId: string | null;
agentId: string;
heartbeatRunId: string; heartbeatRunId: string;
persistedExecutionWorkspace: Pick<ExecutionWorkspace, "id" | "mode"> | null; persistedExecutionWorkspace: Pick<ExecutionWorkspace, "id" | "mode"> | null;
}): Promise<EnvironmentRuntimeLeaseRecord> { }): Promise<EnvironmentRuntimeLeaseRecord> {
@@ -280,6 +281,7 @@ export function environmentRunOrchestrator(
companyId: input.companyId, companyId: input.companyId,
environment, environment,
issueId: input.issueId, issueId: input.issueId,
agentId: input.agentId,
heartbeatRunId: input.heartbeatRunId, heartbeatRunId: input.heartbeatRunId,
persistedExecutionWorkspace: input.persistedExecutionWorkspace, persistedExecutionWorkspace: input.persistedExecutionWorkspace,
}); });
@@ -103,6 +103,14 @@ export interface EnvironmentDriverAcquireInput {
companyId: string; companyId: string;
environment: Environment; environment: Environment;
issueId: string | null; issueId: string | null;
/**
* UUID of the owning agent. Null for ad-hoc invocations (e.g.
* operator-initiated `Test` probes) that are not tied to a specific agent.
* Threaded through to plugin-backed sandbox providers so they can scope
* lease state (PVCs, subdirs, etc.) per-agent without needing to look it
* up via callback.
*/
agentId: string | null;
/** /**
* UUID of the owning heartbeat run, or null for ad-hoc invocations * UUID of the owning heartbeat run, or null for ad-hoc invocations
* (e.g. operator-initiated `Test` probes) that are not tied to a run. * (e.g. operator-initiated `Test` probes) that are not tied to a run.
@@ -489,6 +497,7 @@ function createSandboxEnvironmentDriver(
// UUID so providers that validate or persist the runId still see // UUID so providers that validate or persist the runId still see
// a well-formed identifier. // a well-formed identifier.
runId: input.heartbeatRunId ?? randomUUID(), runId: input.heartbeatRunId ?? randomUUID(),
...(input.agentId ? { agentId: input.agentId } : {}),
workspaceMode: input.executionWorkspaceMode ?? undefined, workspaceMode: input.executionWorkspaceMode ?? undefined,
}, },
resolvePluginSandboxRpcTimeoutMs(workerConfig), resolvePluginSandboxRpcTimeoutMs(workerConfig),
@@ -897,6 +906,7 @@ function createPluginEnvironmentDriver(
issueId: input.issueId, issueId: input.issueId,
config: parsed.config.driverConfig, config: parsed.config.driverConfig,
runId: input.heartbeatRunId ?? randomUUID(), runId: input.heartbeatRunId ?? randomUUID(),
...(input.agentId ? { agentId: input.agentId } : {}),
workspaceMode: input.executionWorkspaceMode ?? undefined, workspaceMode: input.executionWorkspaceMode ?? undefined,
}); });
@@ -1110,6 +1120,11 @@ export function environmentRuntimeService(
companyId: string; companyId: string;
environment: Environment; environment: Environment;
issueId: string | null; issueId: string | null;
/**
* UUID of the owning agent. Null for ad-hoc invocations (e.g.
* operator-initiated `Test` probes).
*/
agentId: string | null;
/** Null for ad-hoc invocations (e.g. operator-initiated `Test` probes). */ /** Null for ad-hoc invocations (e.g. operator-initiated `Test` probes). */
heartbeatRunId: string | null; heartbeatRunId: string | null;
persistedExecutionWorkspace: Pick<ExecutionWorkspace, "id" | "mode"> | null; persistedExecutionWorkspace: Pick<ExecutionWorkspace, "id" | "mode"> | null;
@@ -1126,6 +1141,7 @@ export function environmentRuntimeService(
companyId: input.companyId, companyId: input.companyId,
environment: input.environment, environment: input.environment,
issueId: input.issueId, issueId: input.issueId,
agentId: input.agentId,
heartbeatRunId: input.heartbeatRunId, heartbeatRunId: input.heartbeatRunId,
executionWorkspaceId: leaseContext.executionWorkspaceId, executionWorkspaceId: leaseContext.executionWorkspaceId,
executionWorkspaceMode: leaseContext.executionWorkspaceMode, executionWorkspaceMode: leaseContext.executionWorkspaceMode,