Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 8 additions & 29 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,27 +115,15 @@ jobs:
id: platform
run: echo "pair=$(echo ${{ matrix.platform }} | tr '/' '-')" >> "$GITHUB_OUTPUT"

- name: Build and push slim
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
target: slim
platforms: ${{ matrix.platform }}
push: true
tags: ${{ env.IMAGE }}:slim-${{ steps.platform.outputs.pair }}
cache-from: type=gha,scope=slim-${{ steps.platform.outputs.pair }}
cache-to: type=gha,mode=max,scope=slim-${{ steps.platform.outputs.pair }}

- name: Build and push full
uses: docker/build-push-action@v6
with:
context: .
target: full
platforms: ${{ matrix.platform }}
push: true
tags: ${{ env.IMAGE }}:full-${{ steps.platform.outputs.pair }}
cache-from: type=gha,scope=full-${{ steps.platform.outputs.pair }}
cache-to: type=gha,mode=max,scope=full-${{ steps.platform.outputs.pair }}
tags: ${{ env.IMAGE }}:build-${{ steps.platform.outputs.pair }}
cache-from: type=gha,scope=build-${{ steps.platform.outputs.pair }}
cache-to: type=gha,mode=max,scope=build-${{ steps.platform.outputs.pair }}

merge-docker:
needs: build-docker
Expand All @@ -155,22 +143,13 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create slim multi-arch manifest
run: |
docker buildx imagetools create \
--tag ${{ env.IMAGE }}:${{ needs.build-docker.outputs.version }}-slim \
--tag ${{ env.IMAGE }}:slim \
${{ env.IMAGE }}:slim-linux-amd64 \
${{ env.IMAGE }}:slim-linux-arm64

- name: Create full multi-arch manifest
- name: Create multi-arch manifest
run: |
docker buildx imagetools create \
--tag ${{ env.IMAGE }}:${{ needs.build-docker.outputs.version }}-full \
--tag ${{ env.IMAGE }}:full \
--tag ${{ env.IMAGE }}:${{ needs.build-docker.outputs.version }} \
--tag ${{ env.IMAGE }}:latest \
${{ env.IMAGE }}:full-linux-amd64 \
${{ env.IMAGE }}:full-linux-arm64
${{ env.IMAGE }}:build-linux-amd64 \
${{ env.IMAGE }}:build-linux-arm64

- name: Log in to Fly registry
if: github.repository_owner == 'spacedriveapp'
Expand Down
50 changes: 49 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ arrow-array = "57.3.0"
arrow-schema = "57.3.0"

# Browser automation
chromiumoxide = { version = "0.8", features = ["tokio-runtime"], default-features = false }
chromiumoxide = { version = "0.8", features = ["tokio-runtime", "_fetcher-rustls-tokio"], default-features = false }
chromiumoxide_cdp = "0.8"

# Templating for prompts
Expand Down
48 changes: 21 additions & 27 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,21 @@ RUN SPACEBOT_SKIP_FRONTEND_BUILD=1 cargo build --release \
&& mv /build/target/release/spacebot /usr/local/bin/spacebot \
&& cargo clean -p spacebot --release --target-dir /build/target

# ---- Slim stage ----
# Minimal runtime with just the binary. No browser.
FROM debian:bookworm-slim AS slim
# ---- Runtime stage ----
# Minimal runtime with Chrome runtime libraries for fetcher-downloaded Chromium.
# Chrome itself is downloaded on first browser tool use and cached on the volume.
FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libsqlite3-0 \
curl \
gh \
bubblewrap \
&& rm -rf /var/lib/apt/lists/*

COPY --from=builder /usr/local/bin/spacebot /usr/local/bin/spacebot
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

ENV SPACEBOT_DIR=/data
ENV SPACEBOT_DEPLOYMENT=docker
EXPOSE 19898 18789

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:19898/api/health || exit 1

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["spacebot", "start", "--foreground"]

# ---- Full stage ----
# Slim + Chromium for browser workers.
FROM slim AS full

RUN apt-get update && apt-get install -y --no-install-recommends \
chromium \
openssh-server \
# Chrome runtime dependencies — required whether Chrome is system-installed
Comment thread
jamiepine marked this conversation as resolved.
# or downloaded by the built-in fetcher. The fetcher provides the browser
# binary; these are the shared libraries it links against.
fonts-liberation \
libnss3 \
libatk-bridge2.0-0 \
Expand All @@ -91,5 +74,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libxtst6 \
&& rm -rf /var/lib/apt/lists/*

ENV CHROME_PATH=/usr/bin/chromium
ENV CHROME_FLAGS="--no-sandbox --disable-dev-shm-usage --disable-gpu"
COPY --from=builder /usr/local/bin/spacebot /usr/local/bin/spacebot
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

ENV SPACEBOT_DIR=/data
ENV SPACEBOT_DEPLOYMENT=docker
EXPOSE 19898 18789

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:19898/api/health || exit 1

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["spacebot", "start", "--foreground"]
1 change: 0 additions & 1 deletion fly.staging.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ primary_region = "iad"

[build]
dockerfile = "Dockerfile"
target = "full"

[env]
SPACEBOT_DIR = "/data"
Expand Down
1 change: 0 additions & 1 deletion fly.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ primary_region = "iad"

[build]
dockerfile = "Dockerfile"
target = "full"

[env]
SPACEBOT_DIR = "/data"
Expand Down
52 changes: 34 additions & 18 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,9 @@ pub struct BrowserConfig {
pub executable_path: Option<String>,
/// Directory for storing screenshots and other browser artifacts.
pub screenshot_dir: Option<PathBuf>,
/// Directory for caching a fetcher-downloaded Chromium binary.
/// Populated from `{instance_dir}/chrome_cache` during config resolution.
pub chrome_cache_dir: PathBuf,
}

impl Default for BrowserConfig {
Expand All @@ -880,6 +883,7 @@ impl Default for BrowserConfig {
evaluate_enabled: false,
executable_path: None,
screenshot_dir: None,
chrome_cache_dir: PathBuf::from("chrome_cache"),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
}
Expand Down Expand Up @@ -4121,10 +4125,13 @@ impl Config {
let mut api = ApiConfig::default();
api.bind = hosted_api_bind(api.bind);

let mut defaults = DefaultsConfig::default();
defaults.browser.chrome_cache_dir = instance_dir.join("chrome_cache");

Ok(Self {
instance_dir: instance_dir.to_path_buf(),
llm,
defaults: DefaultsConfig::default(),
defaults,
agents,
links: Vec::new(),
groups: Vec::new(),
Expand Down Expand Up @@ -4729,23 +4736,31 @@ impl Config {
.unwrap_or(base_defaults.warmup.startup_delay_secs),
})
.unwrap_or(base_defaults.warmup),
browser: toml
.defaults
.browser
.map(|b| {
let base = &base_defaults.browser;
BrowserConfig {
enabled: b.enabled.unwrap_or(base.enabled),
headless: b.headless.unwrap_or(base.headless),
evaluate_enabled: b.evaluate_enabled.unwrap_or(base.evaluate_enabled),
executable_path: b.executable_path.or_else(|| base.executable_path.clone()),
screenshot_dir: b
.screenshot_dir
.map(PathBuf::from)
.or_else(|| base.screenshot_dir.clone()),
}
})
.unwrap_or_else(|| base_defaults.browser.clone()),
browser: {
let chrome_cache_dir = instance_dir.join("chrome_cache");
toml.defaults
.browser
.map(|b| {
let base = &base_defaults.browser;
BrowserConfig {
enabled: b.enabled.unwrap_or(base.enabled),
headless: b.headless.unwrap_or(base.headless),
evaluate_enabled: b.evaluate_enabled.unwrap_or(base.evaluate_enabled),
executable_path: b
.executable_path
.or_else(|| base.executable_path.clone()),
screenshot_dir: b
.screenshot_dir
.map(PathBuf::from)
.or_else(|| base.screenshot_dir.clone()),
chrome_cache_dir: chrome_cache_dir.clone(),
}
})
.unwrap_or_else(|| BrowserConfig {
chrome_cache_dir,
..base_defaults.browser.clone()
})
},
mcp: default_mcp,
brave_search_key: toml
.defaults
Expand Down Expand Up @@ -4935,6 +4950,7 @@ impl Config {
.screenshot_dir
.map(PathBuf::from)
.or_else(|| defaults.browser.screenshot_dir.clone()),
chrome_cache_dir: defaults.browser.chrome_cache_dir.clone(),
}),
mcp: match a.mcp {
Some(mcp_servers) => Some(
Expand Down
Loading