Skip to content

refactor: monorepo with the Python and TypeScript packages - #3

Merged
OndrejDrapalik merged 26 commits into
mainfrom
refactor/monorepo
Oct 26, 2026
Merged

OndrejDrapalik merged 26 commits into
mainfrom
refactor/monorepo

Conversation

@OndrejDrapalik

Copy link
Copy Markdown
Collaborator

Summary

Moves e2b-dev/e2b-adk-plugin-js into this repo, laid out like e2b-dev/claude-toolsets: one repo, one release workflow, both packages on one version.

packages/e2b-adk-python/   e2b-adk on PyPI (moved as-is)
packages/e2b-adk-js/       @e2b/adk on npm (e2b-adk-plugin-js@main, history kept)
.changeset/                @e2b/adk and @e2b/adk-python share one version
.github/workflows/         ci.yml (Python 3.10-3.13, Node 22/24), release.yml (changesets, manual dispatch)

Merge with "Create a merge commit", not squash. chore: import e2b-adk-plugin-js history merges the 19 JS commits in, so git log --follow packages/e2b-adk-js/... and blame keep Maksim's history. A squash would flatten it.

Review guide

Most of the +9.6k lines are the imported JS repo and pnpm-lock.yaml. The parts worth reading:

  • 0a5df30 root package.json, pnpm-workspace.yaml, the JS package.json (adds repository with directory for npm provenance, drops packageManager), packages/e2b-adk-python/package.json (wraps uv so pnpm and changesets drive it), root README.
  • 51952e4 release.yml, adapted from claude-toolsets: workflow_dispatch on main only, changeset version syncs the Python version through uv version, then uv publish and changeset publish over OIDC trusted publishing.

Behavior changes worth knowing:

  • pnpm 10 → 11.19.0 (matches claude-toolsets). pnpm 11 rejects unapproved install scripts, so allowBuilds denies the five the JS repo already skipped under pnpm 10. No JS dependency changed version in the lockfile.
  • Python CI drops twine check: a hatchling release newer than main's last green run (2026-10-10) emits Metadata 2.5, which the locked twine 6.2.0 rejects, so main's own next CI run would fail the same way. Building is uv build, and uv publish validates on upload.
  • Python releases move from "publish a GitHub release" to changesets: pnpm changeset, merge, then gh workflow run release.yml --ref main.
  • The root README keeps a ## Configuration heading so the #configuration links in Add E2B to the integrations catalog google/adk-docs#2155 and e2b-dev/docs still resolve.

Before the first release

  • Create a deployment environment limited to main
  • Make VERSION_BUMPER_APPID / VERSION_BUMPER_SECRET available to this repo
  • PyPI e2b-adk: add a trusted publisher for release.yml + deployment
  • npm @e2b/adk: first publish by hand, then a trusted publisher for release.yml + deployment

After merge

Test plan

  • pnpm check from the root: Python ruff, mypy, 72 tests, uv build; JS typecheck, eslint, prettier, 119 tests, build
  • Throwaway copy: a JS-only changeset through pnpm run version bumps both packages to 0.2.0 and syncs pyproject.toml and uv.lock
  • npm pack --dry-run ships only dist, README, LICENSE, package.json; the sdist still holds the package, tests and examples
  • CI green on this PR

max-sudolabs and others added 24 commits September 22, 2026 15:56
Each ADK session gets its own lazily created sandbox, so a module-level
agent serves concurrent users and keeps files and kernels across messages
and confirmation pauses. ADK close() no longer kills anything; the
application releases workspaces with destroySession() and destroyAll().

- Operations of one session are serialized; a cancelled waiter has no
  SDK side effects and never lets later work overtake the active one.
- run_command runs in its own process group and is killed as a group on
  deadline or abort; run_code restarts its per-language kernel.
- timeoutMs is 1..maxOperationMs (default 10 minutes); the deadline
  starts when the operation runs.
- A paused sandbox is resumed; a missing one is reported once with
  workspace_expired, then a new workspace is created.
- Background commands no longer die at the SDK's 60 s default.
- The build cleans dist before compiling.
Rewrite the README and data-analysis example for a module-level agent
with explicit destroySession() cleanup. Extend the live harness to cover
stop mechanisms, pause/resume, expiry, background lifetime and a
multi-user conversation, with an optional test-only OpenAI model.
- destroy() waits for a sandbox that is still being created and kills
  it; if that kill fails the handle is kept, reuse is blocked and a
  retry works.
- A stopped command counts as gone only when the process-group kill
  succeeds or reports that no process is left, and the command exits.
  Otherwise the workspace is blocked until destroySession(); there is
  no leader-only fallback.
- Every async setup step rechecks destroy, block and cancellation
  before side effects, and a result is not reported as a success after
  a destroy.
- The deadline covers command start and kernel start-up. A handle that
  arrives after the deadline is killed; code that never started does
  not claim a kernel restart.
A rejected SDK call does not prove that nothing ran. A command start
fails as an ordinary error only when the sandbox refuses it before
creating a process (InvalidArgumentError, e.g. a missing cwd); any other
start failure blocks the workspace until destroySession(). A lost
command stream is followed by a process-group kill and a lost code
stream by a kernel restart before the error is returned; if either
cannot be confirmed, the workspace is blocked. Background starts follow
the same rule.
After a lost code stream the kernel is restarted, so its variables are
gone; the result now says so with kernel_restarted: true instead of a
generic failure. A context the kernel server no longer knows returns
kernel_reset: true and says the next call starts an empty kernel. Both
state that sandbox files are kept. The direct executor reports the same
text in stderr.
Sandboxes are created with adkAppName, adkUserId and adkSessionId in
their metadata. A process that does not hold a session's sandbox lists
by that metadata and connects to the oldest match, resuming a paused
one; only when none exists does it create, and if another instance
created one at the same moment the older sandbox wins and the newer is
killed. This is the model of E2B's Vercel AI SDK and Mastra integrations.

- Lifetime is extended with connect(), which never shortens what another
  instance granted; a sandbox-level 404 is reported as expiry.
- run_code uses the sandbox's default kernel per language, shared by
  every instance; restarts look the kernel up with listCodeContexts().
- A sandbox destroyed from another process is reported as expired, not
  as a blocked workspace.
- destroySession() also kills session sandboxes this process never
  held, including after a restart.
- Tests run two workspaces or toolsets over a registry double of the
  control plane; scripts/live-processes.ts does it with three real
  processes.
- A namespace option becomes adkNamespace in the sandbox metadata used
  to find, reuse and destroy a session's sandbox, so deployments that
  share one E2B API key and app name stay apart.
- When the list after a create fails, the just-created sandbox is
  discarded instead of used; if that kill fails, the workspace stays
  blocked until destroySession() retries.
- A deadline that fires before the language kernel exists waits for the
  in-flight request to settle within the recovery window and restarts
  the kernel that came up; if the request never settles, the workspace
  is blocked.
- README and guide: operations are serialized per instance only, and
  create-race convergence is best effort.
…be confirmed stopped

- adkNamespace is always written ('default' when unset): E2B's list matches
  any sandbox containing the queried pairs, so an untagged instance could
  find and destroy a namespaced deployment's sandbox
- one stop path for code whose request already went out: restart the listed
  kernel, else let the request settle and restart the kernel it started,
  return the result if the code finished, otherwise block the workspace;
  kernel_restarted is reported only after an actual restart
- maxOperationMs is capped at the largest delay setTimeout honours
- README/guide: race resolution is best effort; destroyAll() covers the
  workspaces this instance knows
@cla-bot cla-bot Bot added the cla-signed label Oct 12, 2026
# Conflicts:
#	.github/workflows/release.yml
PyPI already has e2b-adk 0.1.1, and the fixed changesets group counts
from package.json, so the first shared release lands on 0.1.2.
@OndrejDrapalik
OndrejDrapalik merged commit a5d1147 into main Oct 26, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants