Skip to content

feat(agents): embedder docker-sandbox options + modelCatalog on AgentHandlerResult#4569

Merged
balegas merged 5 commits into
mainfrom
feat/agents-docker-sandbox-options
Jun 15, 2026
Merged

feat(agents): embedder docker-sandbox options + modelCatalog on AgentHandlerResult#4569
balegas merged 5 commits into
mainfrom
feat/agents-docker-sandbox-options

Conversation

@balegas

@balegas balegas commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What

  • BuiltinAgentHandlerOptions.dockerSandbox?: { image, allowFloatingTag, env, extraMounts } — threads into the built-in docker sandbox profile's dockerSandbox() call (which already supports all of these). Custom mounts append after the working-directory mount.
  • AgentHandlerResult.modelCatalog — exposes the catalog createBuiltinAgentHandler already builds.
  • Exports: resolveBuiltinModelConfig, resolveDockerSandboxOpts, and types BuiltinModelCatalog, BuiltinAgentModelConfig, BuiltinDockerSandboxOptions, BuiltinDockerSandboxMount.

Why

OpenFactory registers a custom Discord-facing agent entity alongside horton/worker. It needs (a) a sandbox image with git + gh + a GitHub-App token helper baked in, plus the GH_APP env/key mount inside the container, and (b) the same model-arg resolution the built-in agents use, without re-implementing the catalog.

Tests

packages/agents/test/docker-sandbox-options.test.ts covers the option merge (cwd-mount only, full passthrough, mount append, empty).

🤖 Generated with Claude Code

Notes for reviewers

  • BuiltinDockerSandboxMount intentionally duplicates the runtime's mount item shape instead of importing DockerSandboxOpts — that type only exists on the @electric-ax/agents-runtime/sandbox/docker subpath, which this package deliberately keeps out of its top-level import graph (docker code is reached via dynamic import only).
  • env / extraMounts extend the existing embedder/operator trust boundary: same trust level as the embedder process itself, and extraMounts stays behind the runtime's docker-socket guard.

…HandlerResult

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Electric Agents Desktop Builds

Build artifacts for commit 58d5492.

Platform Status Artifact
macOS Apple Silicon Passed DMG
macOS Intel Passed DMG
Windows x64 Passed Installer
Linux x64 Passed AppImage / deb

Workflow run

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.92308% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.56%. Comparing base (73c6f89) to head (58d5492).
⚠️ Report is 7 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/agents/src/bootstrap.ts 76.92% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4569      +/-   ##
==========================================
+ Coverage   56.67%   58.56%   +1.89%     
==========================================
  Files         327      378      +51     
  Lines       37935    41689    +3754     
  Branches    10938    11835     +897     
==========================================
+ Hits        21498    24416    +2918     
- Misses      16401    17198     +797     
- Partials       36       75      +39     
Flag Coverage Δ
packages/agents 72.43% <76.92%> (+1.05%) ⬆️
packages/agents-mcp 77.70% <ø> (?)
packages/agents-mobile 78.81% <ø> (+3.32%) ⬆️
packages/agents-runtime 82.02% <ø> (-0.45%) ⬇️
packages/agents-server 74.83% <ø> (-0.03%) ⬇️
packages/agents-server-ui 6.19% <ø> (-0.07%) ⬇️
packages/electric-ax 46.42% <ø> (ø)
packages/experimental 87.73% <ø> (?)
packages/react-hooks 86.48% <ø> (?)
packages/start 82.83% <ø> (?)
packages/typescript-client 91.71% <ø> (?)
packages/y-electric 56.05% <ø> (?)
typescript 58.56% <76.92%> (+1.89%) ⬆️
unit-tests 58.56% <76.92%> (+1.89%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…set bullets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@balegas balegas added the claude label Jun 15, 2026
@claude

claude Bot commented Jun 15, 2026

Copy link
Copy Markdown

Claude Code Review

Summary

This PR adds two embedder customization hooks to @electric-ax/agents: BuiltinAgentHandlerOptions.dockerSandbox (image/env/mounts passthrough to the built-in docker profile) and modelCatalog on AgentHandlerResult. Small, additive, backward-compatible, with a changeset and a focused unit test. The only change since the last review (58d5492) is a CI-prettier formatting fix to the drift-guard import() line — no functional change. Ready to merge.

What's Working Well

  • Clean, backward-compatible merge. resolveDockerSandboxOpts preserves prior behavior exactly: with no cwd mount and no custom mounts, extraMounts is omitted (matching the old undefined), and the conditional spreads keep absent keys absent rather than emitting undefined.
  • Security boundary correctly reasoned and documented. makeBinds in agents-runtime/.../docker.ts:940 applies the docker-socket guard (literal + realpath) unconditionally to every extraMounts entry, so embedder-supplied mounts can't smuggle in docker.sock. The changeset and BuiltinDockerSandboxOptions JSDoc both mark env/extraMounts as embedder/operator-trust inputs.
  • modelCatalog: BuiltinModelCatalog (non-nullable) is safe. The early if (!modelCatalog) return null guard narrows the BuiltinModelCatalog | null from createBuiltinModelCatalog before the result object is built.
  • Compile-time drift guard still sound after the reformat. _AssertMountCompat asserts BuiltinDockerSandboxMount extends NonNullable<DockerSandboxOpts['extraMounts']>[number] — correct direction, mutable→readonly assignment holds, and the type-position import(...) is fully erased (no runtime dependency, docker subpath stays out of the eager import graph). The 58d5492 reformat only wraps the NonNullable<...> across lines and moves the eslint-disable-next-line quotes directive onto the physical line immediately above the string-literal import(...) — directive placement is correct (ESLint directives operate on physical lines), so both prettier and the quotes rule are satisfied.
  • Tests cover the meaningful branches of the merge helper (cwd-only, full passthrough, append order, empty).

Issues Found

Critical (Must Fix)

None.

Important (Should Fix)

None.

Suggestions (Nice to Have)

None outstanding — all four suggestions from the prior iterations were resolved (see Previous Review Status). One residual, purely-informational note:

patch bump (carried, resolved-in-spirit). With resolveDockerSandboxOpts dropped from the public surface, the remaining additive surface is new optional input fields plus a returned object field — a defensible patch for a 0.x package. No change requested.

Issue Conformance

No linked issue — per project convention, a soft warning; a tracking issue would help future archaeology. The PR description thoroughly explains the motivation (OpenFactory's Discord-facing agent needing a tooling-baked image + GH App key mount and shared model resolution). Implementation matches the stated scope with no scope creep.

Test Coverage

Codecov reports 3 uncovered lines in bootstrap.ts (76.92% patch) — the wiring inside the docker branch of buildBuiltinSandboxProfiles, which needs a live Docker daemon to exercise. Acceptable, given the pure merge logic is fully unit-tested. No new error paths introduced.

Monorepo Awareness

  • Changeset present (.changeset/openfactory-sandbox-options.md, patch) and consistent with index.ts.
  • No breaking API changes: existing signatures unchanged; AgentHandlerResult gains a required field, but that's a returned object (additive for consumers).
  • No cross-package contract changes to the HTTP API or TS client.

Previous Review Status

All prior suggestions remain addressed; no regressions since iteration 3.

The single new commit (58d5492) is a formatting-only fix for the CI prettier check. No new issues introduced.


Review iteration: 4 | 2026-06-15

balegas and others added 3 commits June 15, 2026 12:31
0.4.17 already shipped without these exports, so release as a patch (0.4.18)
rather than a minor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop `resolveDockerSandboxOpts` from the public `index.ts` exports (and the
  changeset) — it's an internal merge helper; the unit test imports it from
  source, and no other consumer exists. JSDoc updated accordingly.
- Document that custom `extraMounts` must not target the `/work` cwd mount
  (a colliding bind fails opaquely at container create).
- Add a zero-runtime compile-time drift guard asserting
  `BuiltinDockerSandboxMount` stays assignable to the runtime's mount shape
  (inline `import(...)` type is fully erased).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI prettier check wraps the long NonNullable<import(...)> type; move the
eslint-disable-next-line directly above the wrapped import line so both
prettier and the `quotes` rule are satisfied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@balegas

balegas commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

The failing build was the Prettier formatting check (not a compile error): the review-fix added a drift-guard whose long NonNullable<import(...)> type line gets wrapped by Prettier, which then split the import() away from its eslint-disable-next-line quotes comment.

Fixed in 58d5492 by moving the disable comment directly above the wrapped import() line, so Prettier, ESLint (quotes), and tsc are all satisfied. Verified locally:

  • prettier --check packages/agents/src/bootstrap.ts → clean
  • pnpm -C packages/agents stylecheck → clean
  • pnpm -C packages/agents typecheck → clean
  • pnpm -C packages/agents test docker-sandbox-options → 4 passed

For context, the review suggestions were addressed in the prior commits: dropped resolveDockerSandboxOpts from the public index.ts/changeset (internal helper; the test imports from source), documented the /work mount-collision footgun, and added the compile-time mount-shape drift guard.

@balegas balegas merged commit 6fc36d8 into main Jun 15, 2026
67 checks passed
@balegas balegas deleted the feat/agents-docker-sandbox-options branch June 15, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants