wireAgentCore function
WiredAgentCore
wireAgentCore({
- required HostCapabilityProfile profile,
- required AgentCoreServices services,
Wires the agent core for profile over services: run-narrows the
profile against the provided services, builds the plan (E1 loud on
anything still wired without its services), constructs the env chain
and the canonical tool list.
Implementation
WiredAgentCore wireAgentCore({
required HostCapabilityProfile profile,
required AgentCoreServices services,
}) {
final runProfile = _narrowToServices(
profile: profile,
present: services.providedServiceNames,
);
final plan = HostWiringBuilder(
profile: runProfile,
// E1 input: the narrowed profile only leaves wired what the bundle
// provides, so the names themselves satisfy the service contract.
platformServices: {
for (final name in services.providedServiceNames) name: services,
},
).build();
// ---- env chain ----
var env = services.baseEnv;
SandboxedExecutionEnv? sandboxEnv;
if (plan.planFor(HostCapability.sandboxEnv) is WiredCapability) {
final sandbox =
services.sandbox ??
(throw HostWiringException(
'Profile "${plan.profile.name}" wires the sandbox capability but '
'the host provided no SandboxServices (E1: name the missing '
'service, never null-crash at runtime).',
));
sandboxEnv = SandboxedExecutionEnv(
env,
sandbox.spec,
homeDir: sandbox.homeDir,
workspaceRoot: env.cwd,
pathProbe: sandbox.pathProbe,
os: sandbox.os,
onWarning: sandbox.onWarning,
);
env = sandboxEnv;
}
final sessionVars = services.sessionEnvVars;
if (sessionVars != null) {
env = SessionVarsExecutionEnv(env, sessionVars);
}
final sandbox = sandboxEnv;
final networkGate = sandbox == null
? null
: CubeNetworkGate(() => sandbox.activeSpec);
// ---- env-dependent services ----
final shellJobs = services.shellJobsFactory?.call(env);
final configService = services.configServiceFactory?.call(env);
// backgroundShellJobs is PLAN-gated, not factory-gated (review, #1230):
// "off means absent from tools AND surfaced tokens" — a host that
// profiles the capability off but still provides a factory must not
// see the bash_job board.
final gatedShellJobs =
plan.planFor(HostCapability.backgroundShellJobs) is WiredCapability
? shellJobs
: null;
// ---- host extensions (slice 4, HostExtensionApi) ----
// The surface RIDES the hostExtensionApi capability cell: a profile
// declaring it off hides every declared extension with the cell's
// reason — the same hide-with-reason contract as any off capability
// (E8). Declared-but-unenforced would make the cell decorative (E2:
// silence is not a declaration). E6 was enforced at construction
// (every built-in profile declared); below, the builder resolves each
// extension against the profile the host actually wires (custom
// profiles included — a missing state is a wire-time E6 violation).
// The E7 collision check runs after the task complex assembles.
final extensionCell = plan.planFor(HostCapability.hostExtensionApi);
final extensionWiring = extensionCell is WiredCapability
? _wireExtensions(
profileName: profile.name,
extensions: services.extensions,
)
: [
for (final extension in services.extensions)
WiredHostExtension(
extension: extension,
tools: const [],
hiddenReason: (extensionCell as HiddenCapability).reason,
),
];
// Tools first, core second: the list rides the constructor so a wired
// core can never exist without its tools. The agent closures read the
// late-bound agent through the (already-assigned by first use) core.
late final WiredAgentCore core;
final sdkTools = _buildCoreTools(
plan: plan,
env: env,
networkGate: networkGate,
shellJobs: gatedShellJobs,
services: services,
configService: configService,
currentAgent: () => core._agent,
);
// The wired extension tools splice after the SDK core — the canonical
// tail position the raw hostTools list occupied (slice 4).
final tools = [
...sdkTools,
for (final wired in extensionWiring) ...wired.tools,
];
// The task/subagent complex (slice 3) assembles after the core list —
// children draw it as their tool pool — and reads the late-bound agent
// through the same closure. The fabric assembles independently: the
// MAIN inbox drain rides it wherever messagingFabric wires.
final fabricAssembly = _wireFabric(plan: plan, services: services);
final taskComplex = _wireTaskSurface(
plan: plan,
services: services,
fabric: fabricAssembly?.fabric,
coreTools: tools,
currentAgent: () => core._agent,
);
// E7, over every statically assembled surface — AFTER the complex so
// its gated surface joins the check, BEFORE anything reaches a registry.
_rejectToolIdCollisions({
'the SDK core': sdkTools,
if (taskComplex != null) 'the task surface': taskComplex.tools,
for (final wired in extensionWiring.where((w) => !w.isHidden))
'extension "${wired.extension.name}"': wired.tools,
});
core = WiredAgentCore._(
plan: plan,
services: services,
env: env,
sandboxEnv: sandboxEnv,
networkGate: networkGate,
shellJobs: gatedShellJobs,
tools: tools,
fabric: fabricAssembly?.fabric,
fileFabric: fabricAssembly?.fileFabric,
messagesRoot: fabricAssembly?.messagesRoot,
subagentManager: taskComplex?.subagentManager,
a2aManager: taskComplex?.a2aManager,
subagentHeartbeat: taskComplex?.subagentHeartbeat,
taskConfig: taskComplex?.taskConfig,
taskSurface: taskComplex?.tools ?? const [],
extensions: extensionWiring,
);
return core;
}