BO-7 phase 2: containerize the App Workshop app-builder's session - #257
Merged
Conversation
Follow-up to the code_task containerization: the App Workshop app-builder's interactive chat session — the other Copilot-SDK call site copilot_sandbox.py was built to cover — is now wired in too. New orchestrator.executor._maybe_sandbox_session_workspace(), gated on the SAME allow_session_workspace hook _session_workspace_override already uses to identify this agent shape (never a hardcoded agent name) plus "app_builder" in copilot_sandbox_scope (still default-off; zero behavior change until explicitly enabled). Uses copilot_sandbox.get_or_spawn_sticky's per-thread_id container reuse: unlike code_task's one-shot spawn+stop, a fresh container on every chat turn would have regressed the latency this interactive path doesn't have today. Extracted as its own function (not left inline in run_agent_stream) so it's directly unit-testable, matching how _session_workspace_override/_resolve_effective_agent_dir are already factored out nearby. The T2 build step needed real accommodation, not just a mount: build_t2.mjs runs via `node`, and its host-absolute script path is baked into the app-builder's own system prompt at import time. Mounting the app-builder's repo clone at the IDENTICAL container path makes that baked-in path resolve correctly with zero prompt/agent changes. The shared T2 vendor cache (react/ react-dom/esbuild) mounts at a fresh container path, pointed to via CUSTOM_APPS_T2_VENDOR_DIR — an env var build_t2.mjs already reads on the host, so no script changes either. copilot_sandbox.py gained extra_env support (non-secret only) for this. Dockerfile.copilot-sandbox picked up nodejs — needed only by this call site, but one shared image is simpler than maintaining two. New tests/unit/test_app_builder_sandbox.py locks the gating (session- workspace agent + scope, both required), the mount/env composition, and the fall-back-on-spawn-failure contract, via faked get_or_spawn_sticky calls. Full suite: 2313 passed, 0 regressions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3fbeuEeDLJe56fB34QvtQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #255 (
code_taskcontainerization): wires the App Workshop app-builder's interactive chat session into the samecopilot_sandbox.pysandbox — the second, previously-unwired call site it was already built to cover.orchestrator.executor._maybe_sandbox_session_workspace(), gated on the sameallow_session_workspacehook_session_workspace_overridealready uses to identify this agent shape (never a hardcoded agent name), plus"app_builder"incopilot_sandbox_scope(still default-off — zero behavior change until explicitly enabled).copilot_sandbox.get_or_spawn_sticky's per-thread_idcontainer reuse: unlikecode_task's one-shot spawn+stop, a fresh container on every chat turn would regress the latency this interactive path doesn't have today._session_workspace_override/_resolve_effective_agent_dirare already factored out nearby.The T2 build step needed real accommodation, not just a mount.
build_t2.mjsruns vianode, and its host-absolute script path is baked into the app-builder's own system prompt at import time. Mounting the app-builder's repo clone at the identical container path makes that baked-in path resolve correctly with zero prompt/agent changes. The shared T2 vendor cache (react/react-dom/esbuild) mounts at a fresh container path, pointed to viaCUSTOM_APPS_T2_VENDOR_DIR— an env varbuild_t2.mjsalready reads on the host, so no script changes either.copilot_sandbox.pygainedextra_envsupport (non-secret only) for this, andDockerfile.copilot-sandboxpicked upnodejs.Test plan
tests/unit/test_app_builder_sandbox.py— gating (session-workspace agent + scope, both required), mount/env composition, fall-back-on-spawn-failuredocker compose --profile sandbox configvalidates the updated imagepytest tests/unit/— 2313 passed, 0 regressionsGenerated by Claude Code