The invocation compiler: one plan, compiled once, before any effect (IPL-1).
The compile sequence is fixed and total โ accept, validate, resolve, order,
freeze, diagnose โ and every failure in it raises ConfigurationError with
nothing executed. That guarantee is the reason this module imports no I/O: an
effect-free compiler is what makes "no effect has executed" a fact rather than
an intention, and what makes a plan compilable in a test without a live world.
There is exactly one public compile entry point. A second one would be IPL-2's
forbidden second pipeline, however reasonable its motivation looked.
CompileRequest
dataclass
CompileRequest(config_digest: str, scope: RequestScope = RequestScope(), model: ModelResolution = ModelResolution(), instructions: str | None = None, tools: Sequence[ToolDescriptor] = (), stages: Sequence[StageDescriptor] = (), bindings: ServiceBindings = ServiceBindings(), effect_grants: frozenset[str] = frozenset(), limits: PlanLimits = PlanLimits(), event_program: EventProgram = EventProgram(), capabilities: Sequence[str] = ())
The compiler's only accepted input (IPL-1 step 1).
It is a normalized value, never raw adopter configuration: re-parsing legacy
input inside the compiler is how a second, subtly different interpretation
of a config file gets born.
compile_invocation_plan
compile_invocation_plan(request: CompileRequest) -> InvocationPlan
Compile one immutable, stateless plan. Performs no effect of any kind.
Source code in src/symfonic/kernel/compiler.py
| def compile_invocation_plan(request: CompileRequest) -> InvocationPlan:
"""Compile one immutable, stateless plan. Performs no effect of any kind."""
records: list[DiagnosticRecord] = list(_input_records(request))
# The third gate. A stage's declaration and a capability's grant are each
# checked at construction; this is where the *invocation's* grants land --
# today the facade's baseline, and the seam an adopter-supplied grant will
# arrive through. Checked here so an unknown family cannot enter a plan at
# all, rather than being caught only if some stage happens to want it.
require_known_families(request.effect_grants, subject="the invocation")
validate_event_program(request.event_program)
validate_limits(request.limits)
validate_bindings(request.bindings)
model = _resolve_model(request.model)
tool_manifest = _resolve_tools(request.tools, records)
stage_program, stage_records = _resolve_stages(request, records)
records.extend(stage_records)
records.extend(_binding_records(request.bindings))
records.extend(_grant_records(request))
return InvocationPlan(
identity=PlanIdentity(
plan_id=uuid.uuid4().hex,
config_digest=request.config_digest,
compiled_at=time.time(),
schema_version=SCHEMA_VERSION,
),
scope=request.scope,
model=model,
tool_manifest=tool_manifest,
stage_program=stage_program,
bindings=request.bindings,
effect_grants=frozenset(request.effect_grants),
limits=request.limits,
event_program=request.event_program,
diagnostics=PlanDiagnostics(records=tuple(records)),
)
|
derive_child_plan
derive_child_plan(parent: InvocationPlan, request: CompileRequest) -> InvocationPlan
Compile a child plan by narrowing the parent (IPL-6).
Every widening attempt is rejected here rather than at the point of use.
A sub-agent that could add a tool, a grant, a tenant or a token budget its
parent did not have would make the parent's plan a suggestion.
Source code in src/symfonic/kernel/compiler.py
| def derive_child_plan(parent: InvocationPlan, request: CompileRequest) -> InvocationPlan:
"""Compile a child plan by narrowing the parent (IPL-6).
Every widening attempt is rejected here rather than at the point of use.
A sub-agent that could add a tool, a grant, a tenant or a token budget its
parent did not have would make the parent's plan a suggestion.
"""
child = compile_invocation_plan(request)
_require_narrowing(parent, child)
return InvocationPlan(
identity=PlanIdentity(
plan_id=child.identity.plan_id,
config_digest=child.identity.config_digest,
compiled_at=child.identity.compiled_at,
schema_version=child.identity.schema_version,
parent_plan_id=parent.identity.plan_id,
),
scope=child.scope,
model=child.model,
tool_manifest=child.tool_manifest,
stage_program=child.stage_program,
bindings=child.bindings,
effect_grants=child.effect_grants,
limits=child.limits,
event_program=child.event_program,
diagnostics=child.diagnostics,
)
|