chore: SAVEPOINT
This commit is contained in:
@@ -46,7 +46,7 @@ from ..log import die, info
|
|||||||
from ..manifest import ManifestGitEntry, Manifest
|
from ..manifest import ManifestGitEntry, Manifest
|
||||||
from ..supervise import SupervisePlan
|
from ..supervise import SupervisePlan
|
||||||
from ..util import expand_tilde
|
from ..util import expand_tilde
|
||||||
from ..workspace import WorkspacePlan
|
# from ..workspace import WorkspacePlan
|
||||||
from .print_util import print_multi, visible_agent_env_names
|
from .print_util import print_multi, visible_agent_env_names
|
||||||
from .util import host_skill_dir
|
from .util import host_skill_dir
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ class BottlePlan(ABC):
|
|||||||
egress_plan: EgressPlan
|
egress_plan: EgressPlan
|
||||||
supervise_plan: SupervisePlan | None
|
supervise_plan: SupervisePlan | None
|
||||||
agent_provision: AgentProvisionPlan
|
agent_provision: AgentProvisionPlan
|
||||||
workspace_plan: WorkspacePlan
|
# workspace_plan: WorkspacePlan
|
||||||
|
|
||||||
def print(self, *, remote_control: bool) -> None:
|
def print(self, *, remote_control: bool) -> None:
|
||||||
"""Render the y/N preflight summary to stderr."""
|
"""Render the y/N preflight summary to stderr."""
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ class DockerBottlePlan(BottlePlan):
|
|||||||
|
|
||||||
slug: str
|
slug: str
|
||||||
container_name: str
|
container_name: str
|
||||||
container_name_pinned: bool
|
|
||||||
image: str
|
image: str
|
||||||
derived_image: str # "" -> no derived image
|
|
||||||
runtime_image: str # image actually launched (derived or base)
|
|
||||||
# Absolute path to the Dockerfile that builds `image`. Empty means
|
# Absolute path to the Dockerfile that builds `image`. Empty means
|
||||||
# use the repo's default Dockerfile. Populated to a per-bottle
|
# use the repo's default Dockerfile. Populated to a per-bottle
|
||||||
# state file (~/.bot-bottle/state/<slug>/Dockerfile) after a
|
# state file (~/.bot-bottle/state/<slug>/Dockerfile) after a
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ def _agent_service(plan: DockerBottlePlan) -> dict[str, Any]:
|
|||||||
env.append(name)
|
env.append(name)
|
||||||
|
|
||||||
service: dict[str, Any] = {
|
service: dict[str, Any] = {
|
||||||
"image": plan.runtime_image,
|
"image": plan.image,
|
||||||
"container_name": plan.container_name,
|
"container_name": plan.container_name,
|
||||||
"command": ["sleep", "infinity"],
|
"command": ["sleep", "infinity"],
|
||||||
"networks": {"internal": None},
|
"networks": {"internal": None},
|
||||||
|
|||||||
@@ -97,10 +97,6 @@ def launch(
|
|||||||
plan.image, _REPO_DIR,
|
plan.image, _REPO_DIR,
|
||||||
dockerfile=plan.dockerfile_path,
|
dockerfile=plan.dockerfile_path,
|
||||||
)
|
)
|
||||||
if plan.derived_image:
|
|
||||||
docker_mod.build_image_with_cwd(
|
|
||||||
plan.derived_image, plan.image, plan.workspace_plan
|
|
||||||
)
|
|
||||||
|
|
||||||
internal_network = network_mod.network_name_for_slug(plan.slug)
|
internal_network = network_mod.network_name_for_slug(plan.slug)
|
||||||
egress_network = network_mod.network_egress_name_for_slug(plan.slug)
|
egress_network = network_mod.network_egress_name_for_slug(plan.slug)
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ from __future__ import annotations
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ...agent_provider import PROVIDER_TEMPLATES, agent_provision_plan, get_provider
|
from ...agent_provider import agent_provision_plan, get_provider
|
||||||
from ...env import ResolvedEnv, resolve_env
|
from ...env import ResolvedEnv, resolve_env
|
||||||
from ...log import die
|
from ...log import die
|
||||||
from ...workspace import workspace_plan as resolve_workspace_plan
|
# from ...workspace import workspace_plan as resolve_workspace_plan
|
||||||
from .. import BottleSpec
|
from .. import BottleSpec
|
||||||
from ..resolve_common import (
|
from ..resolve_common import (
|
||||||
merge_provision_env_vars,
|
merge_provision_env_vars,
|
||||||
@@ -30,14 +30,17 @@ from ..resolve_common import (
|
|||||||
)
|
)
|
||||||
from . import util as docker_mod
|
from . import util as docker_mod
|
||||||
from .bottle_plan import DockerBottlePlan
|
from .bottle_plan import DockerBottlePlan
|
||||||
from ...bottle_state import (
|
# from ...bottle_state import (
|
||||||
clear_preserve_marker,
|
# # clear_preserve_marker,
|
||||||
per_bottle_dockerfile,
|
# per_bottle_dockerfile,
|
||||||
per_bottle_dockerfile_path,
|
# per_bottle_dockerfile_path,
|
||||||
per_bottle_image_tag,
|
# per_bottle_image_tag,
|
||||||
)
|
# )
|
||||||
from .sidecar_bundle import sidecar_bundle_container_name
|
from .sidecar_bundle import sidecar_bundle_container_name
|
||||||
|
|
||||||
|
def preflight():
|
||||||
|
docker_mod.require_docker()
|
||||||
|
|
||||||
|
|
||||||
def resolve_plan(
|
def resolve_plan(
|
||||||
spec: BottleSpec,
|
spec: BottleSpec,
|
||||||
@@ -47,135 +50,57 @@ def resolve_plan(
|
|||||||
"""Resolve Docker-specific names and write scratch files. Trusts
|
"""Resolve Docker-specific names and write scratch files. Trusts
|
||||||
that the agent and its skills/git-gate keys are present —
|
that the agent and its skills/git-gate keys are present —
|
||||||
validation already ran in the base class."""
|
validation already ran in the base class."""
|
||||||
docker_mod.require_docker()
|
preflight()
|
||||||
|
|
||||||
manifest = spec.manifest
|
manifest = spec.manifest
|
||||||
bottle = manifest.bottle_for(spec.agent_name)
|
manifest_bottle = manifest.bottle_for(spec.agent_name)
|
||||||
provider = bottle.agent_provider
|
manfiest_agent_provider = manifest_bottle.agent_provider
|
||||||
provider_obj = get_provider(provider.template)
|
agent_provider = get_provider(manfiest_agent_provider.template)
|
||||||
provider_runtime = provider_obj.runtime
|
|
||||||
guest_home = "/home/node"
|
|
||||||
workspace_plan = resolve_workspace_plan(spec, guest_home=guest_home)
|
|
||||||
|
|
||||||
slug = mint_slug(spec)
|
slug = mint_slug(spec)
|
||||||
|
# FIXME: don't thin the compose project should be directly written to metadata like this,
|
||||||
|
# should probably be a backend specific metadata field for details like this
|
||||||
write_launch_metadata(slug, spec, compose_project=f"bot-bottle-{slug}", backend="docker")
|
write_launch_metadata(slug, spec, compose_project=f"bot-bottle-{slug}", backend="docker")
|
||||||
# Clear any leftover preserve marker from a prior capability-block
|
|
||||||
# so this fresh launch can be cleaned up at session-end unless
|
|
||||||
# the agent triggers another capability-block.
|
|
||||||
clear_preserve_marker(slug)
|
|
||||||
|
|
||||||
# PRD 0016 capability-block: if a per-bottle Dockerfile has been
|
agent_image = agent_provider.runtime.image
|
||||||
# written (via apply_capability_change), the base image becomes
|
agent_dockerfile_path = resolve_manifest_dockerfile(manfiest_agent_provider.dockerfile, spec)
|
||||||
# per_bottle_image_tag(slug) built from that file. --cwd still
|
instance_name = f"bot-bottle-{slug}"
|
||||||
# layers a derived image on top.
|
|
||||||
if provider.template in PROVIDER_TEMPLATES:
|
|
||||||
image = provider_runtime.image
|
|
||||||
else:
|
|
||||||
image = f"bot-bottle-{provider.template}:{slug}"
|
|
||||||
dockerfile_path = str(provider_obj.dockerfile)
|
|
||||||
if per_bottle_dockerfile(slug) is not None:
|
|
||||||
image = per_bottle_image_tag(slug)
|
|
||||||
dockerfile_path = str(per_bottle_dockerfile_path(slug))
|
|
||||||
elif provider.dockerfile:
|
|
||||||
image = f"bot-bottle-{provider.template}:{slug}"
|
|
||||||
dockerfile_path = resolve_manifest_dockerfile(provider.dockerfile, spec)
|
|
||||||
derived_image = ""
|
|
||||||
runtime_image = image
|
|
||||||
if spec.copy_cwd:
|
|
||||||
derived_image = os.environ.get(
|
|
||||||
"BOT_BOTTLE_DERIVED_IMAGE", f"bot-bottle-cwd:{slug}"
|
|
||||||
)
|
|
||||||
runtime_image = derived_image
|
|
||||||
|
|
||||||
default_container = f"bot-bottle-{slug}"
|
|
||||||
pinned_container = os.environ.get("BOT_BOTTLE_CONTAINER", "")
|
|
||||||
container_name_pinned = bool(pinned_container)
|
|
||||||
if container_name_pinned:
|
|
||||||
container_name = pinned_container
|
|
||||||
if docker_mod.container_exists(container_name):
|
|
||||||
die(
|
|
||||||
f"container '{container_name}' already exists "
|
|
||||||
f"(pinned via BOT_BOTTLE_CONTAINER). "
|
|
||||||
f"Remove it with 'docker rm -f {container_name}' or unset the override."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
container_name = ""
|
|
||||||
for candidate in docker_mod.container_name_candidates(default_container):
|
|
||||||
if not docker_mod.container_exists(candidate):
|
|
||||||
container_name = candidate
|
|
||||||
break
|
|
||||||
if not container_name:
|
|
||||||
die(
|
|
||||||
f"could not find a free container name after "
|
|
||||||
f"{default_container}-{docker_mod.MAX_CONTAINER_SUFFIX}; "
|
|
||||||
f"clean up old containers with 'docker rm -f <name>'"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Probe the sidecar-bundle container name for an orphan from a
|
|
||||||
# previous run. Otherwise a stale bundle surfaces as a
|
|
||||||
# docker-create conflict deep inside launch() with no actionable
|
|
||||||
# hint; failing fast here points at the cleanup command.
|
|
||||||
bundle_name = sidecar_bundle_container_name(slug)
|
|
||||||
if docker_mod.container_exists(bundle_name):
|
|
||||||
die(
|
|
||||||
f"sidecar bundle container '{bundle_name}' already exists. "
|
|
||||||
f"This is an orphan from a previous run; clean it up with "
|
|
||||||
f"'./cli.py cleanup' (or 'docker rm -f {bundle_name}') and "
|
|
||||||
f"retry."
|
|
||||||
)
|
|
||||||
|
|
||||||
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
|
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
|
||||||
env_file = agent_dir / "agent.env"
|
env_file = agent_dir / "agent.env"
|
||||||
|
|
||||||
git_gate_plan = prepare_git_gate(bottle, slug)
|
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
|
||||||
|
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)
|
||||||
|
|
||||||
resolved = resolve_env(manifest, spec.agent_name)
|
resolved = resolve_env(manifest, spec.agent_name)
|
||||||
forwarded_env: dict[str, str] = dict(resolved.forwarded)
|
forwarded_env: dict[str, str] = dict(resolved.forwarded)
|
||||||
_write_env_file(resolved, env_file)
|
_write_env_file(resolved, env_file)
|
||||||
|
|
||||||
|
# ==== docker specific setup ====
|
||||||
use_runsc = docker_mod.runsc_available()
|
use_runsc = docker_mod.runsc_available()
|
||||||
agent_provision = agent_provision_plan(
|
|
||||||
template=provider.template,
|
|
||||||
dockerfile=dockerfile_path,
|
|
||||||
state_dir=agent_dir,
|
|
||||||
guest_home=guest_home,
|
|
||||||
forward_host_credentials=provider.forward_host_credentials,
|
|
||||||
auth_token=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(bottle, slug, agent_provision)
|
|
||||||
|
|
||||||
# Current Dockerfile for the agent image. For `--cwd` derived
|
|
||||||
# images the base Dockerfile is what the agent should propose
|
|
||||||
# changes against (the derived layer is just a workspace copy).
|
|
||||||
# (routes.yaml used to land here too but PRD 0017 chunk 3
|
|
||||||
# moved it behind the `list-egress-routes` MCP tool so the
|
|
||||||
# agent gets live state rather than a launch-time snapshot.)
|
|
||||||
supervise_dockerfile_path = (
|
|
||||||
Path(dockerfile_path) if dockerfile_path else provider_obj.dockerfile
|
|
||||||
)
|
|
||||||
dockerfile_content = (
|
|
||||||
supervise_dockerfile_path.read_text(encoding="utf-8")
|
|
||||||
if supervise_dockerfile_path.is_file()
|
|
||||||
else ""
|
|
||||||
)
|
|
||||||
supervise_plan = prepare_supervise(bottle, slug, dockerfile_content=dockerfile_content)
|
|
||||||
|
|
||||||
return DockerBottlePlan(
|
return DockerBottlePlan(
|
||||||
spec=spec,
|
spec=spec,
|
||||||
stage_dir=stage_dir,
|
stage_dir=stage_dir,
|
||||||
slug=slug,
|
slug=slug,
|
||||||
container_name=container_name,
|
container_name=instance_name,
|
||||||
container_name_pinned=container_name_pinned,
|
# container_name_pinned=container_name_pinned,
|
||||||
image=image,
|
image=agent_image,
|
||||||
derived_image=derived_image,
|
dockerfile_path=agent_dockerfile_path,
|
||||||
runtime_image=runtime_image,
|
|
||||||
dockerfile_path=dockerfile_path,
|
|
||||||
env_file=env_file,
|
env_file=env_file,
|
||||||
forwarded_env=forwarded_env,
|
forwarded_env=forwarded_env,
|
||||||
prompt_file=prompt_file,
|
prompt_file=prompt_file,
|
||||||
@@ -184,7 +109,7 @@ def resolve_plan(
|
|||||||
supervise_plan=supervise_plan,
|
supervise_plan=supervise_plan,
|
||||||
use_runsc=use_runsc,
|
use_runsc=use_runsc,
|
||||||
agent_provision=agent_provision,
|
agent_provision=agent_provision,
|
||||||
workspace_plan=workspace_plan,
|
# workspace_plan=workspace_plan,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from pathlib import Path
|
|||||||
from ...agent_provider import PROVIDER_TEMPLATES, agent_provision_plan, get_provider
|
from ...agent_provider import PROVIDER_TEMPLATES, agent_provision_plan, get_provider
|
||||||
from ...backend import BottleSpec
|
from ...backend import BottleSpec
|
||||||
from ...env import resolve_env
|
from ...env import resolve_env
|
||||||
from ...workspace import workspace_plan as resolve_workspace_plan
|
# from ...workspace import workspace_plan as resolve_workspace_plan
|
||||||
from ..resolve_common import (
|
from ..resolve_common import (
|
||||||
merge_provision_env_vars,
|
merge_provision_env_vars,
|
||||||
mint_slug,
|
mint_slug,
|
||||||
@@ -30,6 +30,8 @@ from ..resolve_common import (
|
|||||||
from .bottle_plan import SmolmachinesBottlePlan
|
from .bottle_plan import SmolmachinesBottlePlan
|
||||||
from .util import smolmachines_bundle_subnet, smolmachines_preflight
|
from .util import smolmachines_bundle_subnet, smolmachines_preflight
|
||||||
|
|
||||||
|
def preflight():
|
||||||
|
smolmachines_preflight()
|
||||||
|
|
||||||
def resolve_plan(
|
def resolve_plan(
|
||||||
spec: BottleSpec, *, stage_dir: Path
|
spec: BottleSpec, *, stage_dir: Path
|
||||||
@@ -41,21 +43,19 @@ def resolve_plan(
|
|||||||
pull. Per-bottle guest env + the TSI allow_cidrs land on the
|
pull. Per-bottle guest env + the TSI allow_cidrs land on the
|
||||||
plan for launch to pass straight through to
|
plan for launch to pass straight through to
|
||||||
`machine create` flags."""
|
`machine create` flags."""
|
||||||
smolmachines_preflight()
|
preflight()
|
||||||
|
|
||||||
|
|
||||||
manifest = spec.manifest
|
manifest = spec.manifest
|
||||||
bottle = manifest.bottle_for(spec.agent_name)
|
manifest_bottle = manifest.bottle_for(spec.agent_name)
|
||||||
provider = bottle.agent_provider
|
manfiest_agent_provider = manifest_bottle.agent_provider
|
||||||
provider_obj = get_provider(provider.template)
|
agent_provider = get_provider(manfiest_agent_provider.template)
|
||||||
provider_runtime = provider_obj.runtime
|
|
||||||
guest_home = "/home/node"
|
|
||||||
workspace_plan = resolve_workspace_plan(spec, guest_home=guest_home)
|
|
||||||
|
|
||||||
slug = mint_slug(spec)
|
slug = mint_slug(spec)
|
||||||
write_launch_metadata(slug, spec, compose_project="", backend="smolmachines")
|
write_launch_metadata(slug, spec, compose_project="", backend="smolmachines")
|
||||||
|
|
||||||
|
# ==== smolmachines specific setup ====
|
||||||
subnet, gateway, bundle_ip = smolmachines_bundle_subnet(slug)
|
subnet, gateway, bundle_ip = smolmachines_bundle_subnet(slug)
|
||||||
|
|
||||||
# Agent's env: resolve through resolve_env() so ?prompt entries
|
# Agent's env: resolve through resolve_env() so ?prompt entries
|
||||||
# are prompted and ${HOST_VAR} entries are interpolated — matching
|
# are prompted and ${HOST_VAR} entries are interpolated — matching
|
||||||
# the Docker backend's contract. Forwarded (secret/interpolated)
|
# the Docker backend's contract. Forwarded (secret/interpolated)
|
||||||
@@ -73,36 +73,30 @@ def resolve_plan(
|
|||||||
"SSL_CERT_FILE": "/etc/ssl/certs/ca-certificates.crt",
|
"SSL_CERT_FILE": "/etc/ssl/certs/ca-certificates.crt",
|
||||||
"REQUESTS_CA_BUNDLE": "/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}"
|
||||||
|
|
||||||
git_gate_plan = prepare_git_gate(bottle, slug)
|
|
||||||
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
|
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
|
||||||
|
|
||||||
machine_name = f"bot-bottle-{slug}"
|
|
||||||
if provider.template in PROVIDER_TEMPLATES:
|
|
||||||
agent_image_ref = provider_runtime.image
|
|
||||||
else:
|
|
||||||
agent_image_ref = f"bot-bottle-{provider.template}:{slug}"
|
|
||||||
agent_dockerfile_path = str(provider_obj.dockerfile)
|
|
||||||
if provider.dockerfile:
|
|
||||||
agent_image_ref = f"bot-bottle-{provider.template}:{slug}"
|
|
||||||
agent_dockerfile_path = resolve_manifest_dockerfile(provider.dockerfile, spec)
|
|
||||||
agent_provision = agent_provision_plan(
|
agent_provision = agent_provision_plan(
|
||||||
template=provider.template,
|
template=manfiest_agent_provider.template,
|
||||||
dockerfile=agent_dockerfile_path,
|
dockerfile=agent_dockerfile_path,
|
||||||
state_dir=agent_dir,
|
state_dir=agent_dir,
|
||||||
guest_home=guest_home,
|
guest_home="/home/node", # FIXME: should be coming from the agent plan
|
||||||
guest_env=guest_env,
|
guest_env=guest_env,
|
||||||
forward_host_credentials=provider.forward_host_credentials,
|
forward_host_credentials=manfiest_agent_provider.forward_host_credentials,
|
||||||
auth_token=provider.auth_token,
|
auth_token=manfiest_agent_provider.auth_token,
|
||||||
host_env=dict(os.environ),
|
host_env=dict(os.environ),
|
||||||
trusted_project_path=workspace_plan.workdir,
|
# trusted_project_path=workspace_plan.workdir,
|
||||||
label=spec.label,
|
label=spec.label,
|
||||||
color=spec.color,
|
color=spec.color,
|
||||||
)
|
)
|
||||||
agent_provision = merge_provision_env_vars(agent_provision)
|
agent_provision = merge_provision_env_vars(agent_provision)
|
||||||
|
egress_plan = prepare_egress(manifest_bottle, slug, agent_provision)
|
||||||
egress_plan = prepare_egress(bottle, slug, agent_provision)
|
supervise_plan = prepare_supervise(manifest_bottle, slug)
|
||||||
supervise_plan = prepare_supervise(bottle, slug)
|
git_gate_plan = prepare_git_gate(manifest_bottle, slug)
|
||||||
|
|
||||||
return SmolmachinesBottlePlan(
|
return SmolmachinesBottlePlan(
|
||||||
spec=spec,
|
spec=spec,
|
||||||
@@ -111,7 +105,7 @@ def resolve_plan(
|
|||||||
bundle_subnet=subnet,
|
bundle_subnet=subnet,
|
||||||
bundle_gateway=gateway,
|
bundle_gateway=gateway,
|
||||||
bundle_ip=bundle_ip,
|
bundle_ip=bundle_ip,
|
||||||
machine_name=machine_name,
|
machine_name=instance_name,
|
||||||
agent_image_ref=agent_image_ref,
|
agent_image_ref=agent_image_ref,
|
||||||
guest_env=agent_provision.guest_env,
|
guest_env=agent_provision.guest_env,
|
||||||
prompt_file=prompt_file,
|
prompt_file=prompt_file,
|
||||||
@@ -119,5 +113,5 @@ def resolve_plan(
|
|||||||
egress_plan=egress_plan,
|
egress_plan=egress_plan,
|
||||||
supervise_plan=supervise_plan,
|
supervise_plan=supervise_plan,
|
||||||
agent_provision=agent_provision,
|
agent_provision=agent_provision,
|
||||||
workspace_plan=workspace_plan,
|
# workspace_plan=workspace_plan,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -465,8 +465,6 @@ class Supervise(ABC):
|
|||||||
self,
|
self,
|
||||||
slug: str,
|
slug: str,
|
||||||
stage_dir: Path,
|
stage_dir: Path,
|
||||||
*,
|
|
||||||
dockerfile_content: str = "",
|
|
||||||
) -> SupervisePlan:
|
) -> SupervisePlan:
|
||||||
"""Stage the per-bottle queue dir on the host and the
|
"""Stage the per-bottle queue dir on the host and the
|
||||||
current-config dir under `stage_dir`. Returns the plan;
|
current-config dir under `stage_dir`. Returns the plan;
|
||||||
@@ -476,9 +474,6 @@ class Supervise(ABC):
|
|||||||
queue_dir.mkdir(parents=True, exist_ok=True)
|
queue_dir.mkdir(parents=True, exist_ok=True)
|
||||||
current_config_dir = stage_dir / "current-config"
|
current_config_dir = stage_dir / "current-config"
|
||||||
current_config_dir.mkdir(parents=True, exist_ok=True)
|
current_config_dir.mkdir(parents=True, exist_ok=True)
|
||||||
dockerfile_path = current_config_dir / CURRENT_CONFIG_DOCKERFILE
|
|
||||||
dockerfile_path.write_text(dockerfile_content)
|
|
||||||
dockerfile_path.chmod(0o644)
|
|
||||||
return SupervisePlan(
|
return SupervisePlan(
|
||||||
slug=slug,
|
slug=slug,
|
||||||
queue_dir=queue_dir,
|
queue_dir=queue_dir,
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ def _plan(
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-claude:latest",
|
image="bot-bottle-claude:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-claude:latest",
|
agent_image="bot-bottle-claude:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=Path("/dev/null"), # exists, size 0 → renderer skips env_file
|
env_file=Path("/dev/null"), # exists, size 0 → renderer skips env_file
|
||||||
forwarded_env={"CLAUDE_CODE_OAUTH_TOKEN": "x"},
|
forwarded_env={"CLAUDE_CODE_OAUTH_TOKEN": "x"},
|
||||||
@@ -210,7 +210,7 @@ class TestAgentAlwaysPresent(unittest.TestCase):
|
|||||||
def test_agent_image_uses_runtime_image(self):
|
def test_agent_image_uses_runtime_image(self):
|
||||||
plan = _plan()
|
plan = _plan()
|
||||||
s = bottle_plan_to_compose(plan)["services"]["agent"]
|
s = bottle_plan_to_compose(plan)["services"]["agent"]
|
||||||
self.assertEqual(plan.runtime_image, s["image"])
|
self.assertEqual(plan.agent_image, s["image"])
|
||||||
|
|
||||||
def test_agent_only_on_internal_network(self):
|
def test_agent_only_on_internal_network(self):
|
||||||
s = bottle_plan_to_compose(_plan())["services"]["agent"]
|
s = bottle_plan_to_compose(_plan())["services"]["agent"]
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def _plan(
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-claude:latest",
|
image="bot-bottle-claude:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-claude:latest",
|
agent_image="bot-bottle-claude:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=Path("/tmp/agent.env"),
|
env_file=Path("/tmp/agent.env"),
|
||||||
forwarded_env={},
|
forwarded_env={},
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ def _plan(
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-codex:latest",
|
image="bot-bottle-codex:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-codex:latest",
|
agent_image="bot-bottle-codex:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=Path("/tmp/agent.env"),
|
env_file=Path("/tmp/agent.env"),
|
||||||
forwarded_env={},
|
forwarded_env={},
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def _plan(tmp: str) -> DockerBottlePlan:
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-claude:latest",
|
image="bot-bottle-claude:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-claude:latest",
|
agent_image="bot-bottle-claude:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=stage / "env",
|
env_file=stage / "env",
|
||||||
forwarded_env={},
|
forwarded_env={},
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ def _plan(*, git_user: dict | None = None, # type: ignore
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-claude:latest",
|
image="bot-bottle-claude:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-claude:latest",
|
agent_image="bot-bottle-claude:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=Path("/tmp/agent.env"),
|
env_file=Path("/tmp/agent.env"),
|
||||||
forwarded_env={},
|
forwarded_env={},
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ def _docker_plan(spec: BottleSpec, tmp: str) -> DockerBottlePlan:
|
|||||||
container_name_pinned=False,
|
container_name_pinned=False,
|
||||||
image="bot-bottle-claude:latest",
|
image="bot-bottle-claude:latest",
|
||||||
derived_image="",
|
derived_image="",
|
||||||
runtime_image="bot-bottle-claude:latest",
|
agent_image="bot-bottle-claude:latest",
|
||||||
dockerfile_path="",
|
dockerfile_path="",
|
||||||
env_file=stage / "env",
|
env_file=stage / "env",
|
||||||
forwarded_env={},
|
forwarded_env={},
|
||||||
|
|||||||
Reference in New Issue
Block a user