@@ -268,6 +268,11 @@ export interface AcpxProviderDependencies {
268268 * asks for one prepares nothing.
269269 */
270270 prepareAgent ?: ( agentName : string ) => Operation < void > ;
271+ /** Child-only host inputs for the selected command; never session configuration. */
272+ agentProcessEnv ?: (
273+ agentName : string ,
274+ agentCommand : string ,
275+ ) => Operation < Record < string , string > | undefined > ;
271276 /**
272277 * The native adapters this host has proven and is therefore willing to hand
273278 * a session to. Absent means none: knowing an adapter's command shape is not
@@ -1204,7 +1209,7 @@ function* useAcpxProviderState(
12041209 } ;
12051210 }
12061211
1207- function * runtimeOptions ( ) : Operation < AcpRuntimeOptions > {
1212+ function * runtimeOptions ( agentName ?: string ) : Operation < AcpRuntimeOptions > {
12081213 const dir = yield * agentCwd ( ) ;
12091214 const options : AcpRuntimeOptions = {
12101215 cwd : dir ,
@@ -1213,6 +1218,15 @@ function* useAcpxProviderState(
12131218 permissionMode : providerOptions . permissionMode ,
12141219 nonInteractivePermissions : "deny" ,
12151220 } ;
1221+ if ( agentName !== undefined && dependencies ?. agentProcessEnv !== undefined ) {
1222+ const environment = yield * dependencies . agentProcessEnv (
1223+ agentName ,
1224+ resolveAgentCommand ( registry , agentName ) ,
1225+ ) ;
1226+ if ( environment !== undefined ) {
1227+ options . agentProcessEnv = { ...environment } ;
1228+ }
1229+ }
12161230 if ( mcpServers !== undefined ) {
12171231 options . mcpServers = [ ...mcpServers ] ;
12181232 }
@@ -1253,8 +1267,8 @@ function* useAcpxProviderState(
12531267 * step: an election that suspends part-way through is an election another
12541268 * operation can act between.
12551269 */
1256- function * runtimeBlueprint ( build ?: BoundBuild ) : Operation < AcpRuntimeOptions > {
1257- const base = yield * runtimeOptions ( ) ;
1270+ function * runtimeBlueprint ( build ?: BoundBuild , agentName ?: string ) : Operation < AcpRuntimeOptions > {
1271+ const base = yield * runtimeOptions ( build === undefined ? agentName : undefined ) ;
12581272 const options : AcpRuntimeOptions = {
12591273 ...base ,
12601274 // The acpx callback boundary: `scope.run` returns a Promise-compatible
@@ -1284,12 +1298,18 @@ function* useAcpxProviderState(
12841298 * map no longer names and the next operation builds a second child for the
12851299 * same build. Here the entry is published already reserved.
12861300 */
1287- function electRuntime ( partition : string | undefined , options : AcpRuntimeOptions ) : RuntimeEntry {
1301+ function electRuntime (
1302+ partition : string | undefined ,
1303+ options : AcpRuntimeOptions | undefined ,
1304+ ) : RuntimeEntry {
12881305 const held = partition === undefined ? unbound : runtimes . get ( partition ) ;
12891306 if ( held ) {
12901307 held . active ++ ;
12911308 return held ;
12921309 }
1310+ if ( options === undefined ) {
1311+ throw new Error ( "the selected ACP runtime was released during preparation" ) ;
1312+ }
12931313 const entry : RuntimeEntry = {
12941314 runtime : createRuntime ( options ) ,
12951315 partition,
@@ -1419,10 +1439,6 @@ function* useAcpxProviderState(
14191439 toSession : ( handle : AcpRuntimeHandle , entry : RuntimeEntry ) => ManagedSession ,
14201440 ) : Operation < ManagedSession > {
14211441 return scoped ( function * ( ) : Operation < ManagedSession > {
1422- const partition = build ? partitionOf ( build ) : undefined ;
1423- // Every suspension this needs, taken before anything is decided. What
1424- // follows must not yield, so nothing it depends on may.
1425- const options = yield * runtimeBlueprint ( build ) ;
14261442 let claimed : RuntimeEntry | undefined ;
14271443 let pending : Promise < AcpRuntimeHandle > | undefined ;
14281444 let settled = false ;
@@ -1470,6 +1486,16 @@ function* useAcpxProviderState(
14701486 yield * abandonHandle ( late , "cancelled before the session was established" ) ;
14711487 } ) ;
14721488
1489+ const partition = build
1490+ ? partitionOf ( build )
1491+ : dependencies ?. agentProcessEnv === undefined
1492+ ? undefined
1493+ : `host\u0000${ input . agent } \u0000${ resolveAgentCommand ( registry , input . agent ) } ` ;
1494+ const held = partition === undefined ? unbound : runtimes . get ( partition ) ;
1495+ const options =
1496+ build !== undefined || dependencies ?. agentProcessEnv === undefined || held === undefined
1497+ ? yield * runtimeBlueprint ( build , input . agent )
1498+ : undefined ;
14731499 // One synchronous step: the map is read, an entry is published already
14741500 // claimed if this is the first work to want one, and the ensure is
14751501 // started. Nothing yields in here, so no sibling runs between the
@@ -1533,7 +1559,7 @@ function* useAcpxProviderState(
15331559 // client-native session is created by a native process, and where ACP does
15341560 // serve one, the establishment itself reports being unable to.
15351561 if ( ! validatedAgents . has ( selected ) && ! boundSessions ( selected ) ) {
1536- const base = yield * runtimeOptions ( ) ;
1562+ const base = yield * runtimeOptions ( selected ) ;
15371563 const probe = createRuntime ( { ...base , probeAgent : selected } ) ;
15381564 const report = yield * until ( probe . doctor ( ) ) ;
15391565 if ( ! report . ok ) {
0 commit comments