118 lines
4.4 KiB
Python
118 lines
4.4 KiB
Python
"""smolmachines `_resolve_plan` (PRD 0023 chunks 2d + 4c).
|
|
|
|
Resolves the per-bottle docker subnet + bundle IP and assembles
|
|
the guest env. The agent's docker image build → smolmachine
|
|
pack pipeline runs in `launch.launch`, not here, so the
|
|
dashboard's preflight modal isn't garbled by docker-build output
|
|
before the operator has confirmed.
|
|
|
|
No VM bringup — that's `launch.launch`'s job."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from ...agent_provider import PROVIDER_TEMPLATES, agent_provision_plan, get_provider
|
|
from ...backend import BottleSpec
|
|
from ...env import resolve_env
|
|
# from ...workspace import workspace_plan as resolve_workspace_plan
|
|
from ..resolve_common import (
|
|
merge_provision_env_vars,
|
|
mint_slug,
|
|
prepare_agent_state_dir,
|
|
prepare_egress,
|
|
prepare_git_gate,
|
|
prepare_supervise,
|
|
resolve_manifest_dockerfile,
|
|
write_launch_metadata,
|
|
)
|
|
from .bottle_plan import SmolmachinesBottlePlan
|
|
from .util import smolmachines_bundle_subnet, smolmachines_preflight
|
|
|
|
def preflight():
|
|
smolmachines_preflight()
|
|
|
|
def resolve_plan(
|
|
spec: BottleSpec, *, stage_dir: Path
|
|
) -> SmolmachinesBottlePlan:
|
|
"""Materialize the smolmachines plan. The bundle's docker
|
|
subnet + pinned IP are derived from the slug; the agent's
|
|
`.smolmachine` artifact is built (or cache-hit) here so
|
|
launch's `machine create --from` boots without a registry
|
|
pull. Per-bottle guest env + the TSI allow_cidrs land on the
|
|
plan for launch to pass straight through to
|
|
`machine create` flags."""
|
|
preflight()
|
|
|
|
|
|
manifest = spec.manifest
|
|
manifest_bottle = manifest.bottle_for(spec.agent_name)
|
|
manfiest_agent_provider = manifest_bottle.agent_provider
|
|
agent_provider = get_provider(manfiest_agent_provider.template)
|
|
|
|
slug = mint_slug(spec)
|
|
write_launch_metadata(slug, spec, compose_project="", backend="smolmachines")
|
|
|
|
# ==== smolmachines specific setup ====
|
|
subnet, gateway, bundle_ip = smolmachines_bundle_subnet(slug)
|
|
# Agent's env: resolve through resolve_env() so ?prompt entries
|
|
# are prompted and ${HOST_VAR} entries are interpolated — matching
|
|
# the Docker backend's contract. Forwarded (secret/interpolated)
|
|
# values still reach the guest as -e K=V smolvm flags because
|
|
# smolvm 0.8.0 has no env-file or stdin injection path; this is
|
|
# the known argv-exposure gap documented in PRD 0038.
|
|
# HTTPS_PROXY / GIT_GATE_URL / MCP_SUPERVISE_URL are populated
|
|
# in launch.py after bundle bringup.
|
|
resolved = resolve_env(manifest, spec.agent_name)
|
|
guest_env: dict[str, str] = {
|
|
**resolved.literals,
|
|
**resolved.forwarded,
|
|
"NO_PROXY": "localhost,127.0.0.1",
|
|
"NODE_EXTRA_CA_CERTS": "/etc/ssl/certs/ca-certificates.crt",
|
|
"SSL_CERT_FILE": "/etc/ssl/certs/ca-certificates.crt",
|
|
"REQUESTS_CA_BUNDLE": "/etc/ssl/certs/ca-certificates.crt",
|
|
}
|
|
# ==============
|
|
|
|
agent_dockerfile_path = resolve_manifest_dockerfile(manfiest_agent_provider.dockerfile, spec)
|
|
instance_name = f"bot-bottle-{slug}"
|
|
|
|
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
|
|
|
|
agent_provision = agent_provision_plan(
|
|
template=manfiest_agent_provider.template,
|
|
dockerfile=agent_dockerfile_path,
|
|
state_dir=agent_dir,
|
|
guest_home="/home/node", # FIXME: should be coming from the agent plan
|
|
guest_env=guest_env,
|
|
forward_host_credentials=manfiest_agent_provider.forward_host_credentials,
|
|
auth_token=manfiest_agent_provider.auth_token,
|
|
host_env=dict(os.environ),
|
|
# trusted_project_path=workspace_plan.workdir,
|
|
label=spec.label,
|
|
color=spec.color,
|
|
)
|
|
agent_provision = merge_provision_env_vars(agent_provision)
|
|
egress_plan = prepare_egress(manifest_bottle, slug, agent_provision)
|
|
supervise_plan = prepare_supervise(manifest_bottle, slug)
|
|
git_gate_plan = prepare_git_gate(manifest_bottle, slug)
|
|
|
|
return SmolmachinesBottlePlan(
|
|
spec=spec,
|
|
stage_dir=stage_dir,
|
|
slug=slug,
|
|
bundle_subnet=subnet,
|
|
bundle_gateway=gateway,
|
|
bundle_ip=bundle_ip,
|
|
machine_name=instance_name,
|
|
agent_image_ref=agent_image_ref,
|
|
guest_env=agent_provision.guest_env,
|
|
prompt_file=prompt_file,
|
|
git_gate_plan=git_gate_plan,
|
|
egress_plan=egress_plan,
|
|
supervise_plan=supervise_plan,
|
|
agent_provision=agent_provision,
|
|
# workspace_plan=workspace_plan,
|
|
)
|